golang自定义路由控制实现(一)
由于本人之前一直是Java Coder,在Java web开发中其实大家都很依赖框架,所以当在学习Golang的时候,自己便想着在Go开发中脱离框架,自己动手造框架来练习。通过学习借鉴Java的思想还有部分框架的源码,在golang上面进行实现,从而达到对Java和Golang的同时学习目的,这就很美滋滋了。
Golang中http的设计非常轻量,又兼具很高的扩展性,初学者都可以轻易的设计出自定义的路由功能,使用上十分简单(这里……来吐槽一下Java的Servlet,虽然我也对Java爱得深沉),下面请看Go的Demo。
func HelloServer1(w http.ResponseWriter, req *http.Request) { fmt.Fprint(w,"hello world") } func main() { http.HandleFunc("/test", HelloServer1) err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("ListenAndServe: ", err.Error()) } }
短短的几行代码便可以成功注册一个接口并跑起服务。但是原生的开发方式提供的功能是比较精简的目前几乎所有的Web应用路由实现都是基于http默认的路由器,但是Go自带的路由器有几个限制:
- 不支持参数设定,例如/user/:uid 这种泛类型匹配。
- 无法很好的支持REST模式,无法限制访问的方法,例如上面的例子中,用户访问/foo,可以用GET、POST、DELETE、HEAD等方式访问。
- 一般网站的路由规则太多了,编写繁琐,可以通过struct的方法进行一种简化。
Go有如此限制跟http提供的默认方式有关,我们先看下http两个关键的struct
type ServeMux struct { mu sync.RWMutex m map[string]muxEntry hosts bool // whether any patterns contain hostnames } type muxEntry struct { explicit bool h Handler pattern string }
我们需要重点关键两个地方,一个是ServeMux 中的参数m,它的类型是 map[string]muxEntry ,这里我们自然而然可以想到,参数m负责路由分发。第二个重点则是muxEntry,muxEntry的h Handler
对应的就是我们编写的接口,而围绕这个接口,http并没有其他过多的功能,甚至连像Java中制定一套统一web开发标准都没有。因此http中只是提供最基础的功能,用户则需要以这些功能为基础,进而YY出自己想要的框架或者更丰富的功能。
首先我们问题,能够快速简单的设置Http Method,以方便日后支持RESTFUL的URL规范。有两种简单的做法,第一种做法是使用二维Map ,即map[string]map[string]http.HandlerFunc
,其中一维的键String表示请求method比如post, get 等。二维的键string表示要匹配的URL地址, http.HandlerFunc当然就是处理URL请求的具体方法。第二种做法即是笔者采用的做法,其实是第一种做法演变而来的,HTTP 中Method的种类是固定的,其实我们完全可以用一个数组,而值为map[string]http.HandlerFunc
来实现。
const ( GET = iota POST PUT DELETE CONNECTIBNG HEAD OPTIONS PATCH TRACE )
看完上面常量的设置,想必读者已经知道了我的意思,e.g:array[0]表示GET方法下所有的接口的集合,array[1]表示POST方法下所有的接口的集合基本原理其实也简单,把Get方法下的所有的接口都存储到array[0]的值中,以此推理其他方法。原理简单,但是一个框架的设计必须高内聚低耦合,一个Web框架中路由分发是基础,在该此处上需要建立更多的功能,比如说过滤器等。在初期设计的时候必须保证要有可扩展性,所以笔者认为难点在于此。下面直接上代码,对应的代码有充分的注释。
package odserver import ( "net/http" ) //实现IOdServer的接口,以及http提供ServeHttp方法 type OdServer struct { router MethodMaps } type IOdServer interface { GET(url string, f HandlerFunc) POST(url string, f HandlerFunc) PUT(url string, f HandlerFunc) DELETE(url string, f HandlerFunc) } type HandlerMapped struct { f HandlerFunc } //接口函数单位,即我们编写代码逻辑的函数 type HandlerFunc func(w http.ResponseWriter, req *http.Request) func Default() *OdServer { return &OdServer{ router:NewRouter(), } } //实现Handler接口,匹配方法以及路径 func (o *OdServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { //转发给doHandler进行执行 o.doHandler(w,req) } //判断需要执行的Http Method,从而查找对应的接口并且执行 func (o *OdServer) doHandler(w http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodGet: { if hm, ok := o.router.GetMapping(req.URL.RequestURI()); ok { hm.f(w, req) } } case http.MethodPost: { if hm, ok := o.router.PostMapping(req.URL.RequestURI()); ok { hm.f(w, req) } } case http.MethodDelete: { if hm, ok := o.router.DeleteMapping(req.URL.String()); ok { hm.f(w, req) } } case http.MethodPut: { if hm, ok := o.router.PutMapping(req.URL.String()); ok { hm.f(w, req) } } default: { } } } func (o *OdServer) GET(url string, f HandlerFunc) { o.router.GetAdd(url, HandlerMapped{f: f}) } func (o *OdServer) POST(url string, f HandlerFunc) { o.router.PostAdd(url, HandlerMapped{f: f}) } func (o *OdServer) PUT(url string, f HandlerFunc) { o.router.PutAdd(url, HandlerMapped{f: f}) } func (o *OdServer) DELETE(url string, f HandlerFunc) { o.router.DeleteAdd(url, HandlerMapped{f: f}) }
package odserver /** 提供基本的路由功能,添加路由,查找路由 */ const ( GET = iota POST PUT DELETE CONNECTIBNG HEAD OPTIONS PATCH TRACE ) func NewRouter() MethodMaps { return []handler{ GET: make(handler), POST: make(handler), PUT: make(handler), DELETE: make(handler), } } type MethodMaps [] handler type handler map[string]HandlerMapped //映射路由,获取Get方法下对应的接口 func (m MethodMaps) GetMapping(url string) (HandlerMapped, bool) { if hm, ok := m[GET][url]; ok { return hm, true } return HandlerMapped{}, false } //映射路由,获取Post方法下对应的接口 func (m MethodMaps) PostMapping(url string) (HandlerMapped, bool) { if hm, ok := m[POST][url]; ok { return hm, true } return HandlerMapped{}, false } //映射路由,获取Delete方法下对应的接口 func (m MethodMaps) DeleteMapping(url string) (HandlerMapped, bool) { if hm, ok := m[DELETE][url]; ok { return hm, true } return HandlerMapped{}, false } //映射路由,获取Put方法下对应的接口 func (m MethodMaps) PutMapping(url string) (HandlerMapped, bool) { if hm, ok := m[PUT][url]; ok { return hm, true } return HandlerMapped{}, false } //增加Get方法下的接口 func (m MethodMaps) GetAdd(url string, mapped HandlerMapped) { if _, ok := m.GetMapping(url); ok { panic("duplicate url with get method") } m[GET].SetUrl(url,mapped) } //增加Post方法下的接口 func (m MethodMaps) PostAdd(url string, mapped HandlerMapped) { if _, ok := m.GetMapping(url); ok { panic("duplicate url with Post method") } m[POST].SetUrl(url,mapped) } //增加Put方法下的接口 func (m MethodMaps) PutAdd(url string, mapped HandlerMapped) { if _, ok := m.GetMapping(url); ok { panic("duplicate url with Put method") } m[PUT].SetUrl(url,mapped) } //增加Delete方法下的接口 func (m MethodMaps) DeleteAdd(url string, mapped HandlerMapped) { if _, ok := m.GetMapping(url); ok { panic("duplicate url with Delete method") } m[DELETE].SetUrl(url,mapped) } func (h handler) SetUrl(url string, mapped HandlerMapped) { h[url] = mapped }
如我所说,我觉得学习Golang比较有意思的是,可以将从Java里学到的东西,转之在Golang里尝试实现,不仅学习了Golang,还使得自己对Java的认识进一步提升。如果读者有更好的方法,不吝赐教
参考资料:# Golang学习笔记 - 标准库"net/http"的简析及自制简单路由框架

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析
1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步组件CountDownLatch和CyclicBarrier。这两个同步组件比较常用,也经常被放在一起对比。通过分析这两个同步组件,可使我们对 Java 线程间协同有更深入的了解。同时通过分析其原理,也可使我们做到知其然,并知其所以然。 这里首先来介绍一下 CountDownLatch 的用途,CountDownLatch 允许一个或一组线程等待其他线程完成后再恢复运行。线程可通过调用await方法进入等待状态,在其他线程调用countDown方法将计数器减为0后,处于等待状态的线程即可恢复运行。CyclicBarrier (可循环使用的屏障)则与此不同,CyclicBarrier 允许一组线程到达屏障后阻塞住,直到最后一个线程进入到达屏障,所有线程才恢复运行。它们之间主要的区别在于唤醒等待线程的时机。CountDownLatch 是在计数器减为0后,唤醒等待线程。CyclicBarrie...
- 下一篇
.NET轻量级ORM框架Dapper入门精通
一、课程介绍 本次分享课程包含两个部分《.NET轻量级ORM框架Dapper修炼手册》和《.NET轻量级ORM框架Dapper葵花宝典》,阿笨将带领大家一起领略轻量级ORM框架Dapper的魅力。 本次分享课程适合人群范围: 一、《.NET轻量级ORM框架Dapper修炼手册》适合人群如下: 1、我是一个新手,主要工作面向的是MS SQL Server数据库,那么选择修炼手册一定没错。 2、对Dapper从没有过了解或者了解不全面的同学,想通过学习进一步提升对Dapper的认识。 3、迫切想提高下ADO.NET实战技术以及Transact-SQL的编写能力。 二、《.NET轻量级ORM框架Dapper葵花宝典》适合人群如下: 1、我是一个新手,主要工作面向的是MySQL数据库,那么选择葵花宝典一定没错。 2、在Dapper修炼手册的基础上新增一个Dapper扩展库Dapper.SimpleCRUD。 3、如何运用Dapper操作Mysql数据库以及Dapper如何支持多数据库。 4、学习Dapper在实际项目常用的几种开发架构模式。(简单三层架构模式、工厂模式、Repository架构...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Mario游戏-低调大师作品
- CentOS8编译安装MySQL8.0.19
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- 2048小游戏-低调大师作品
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程