由于本人之前一直是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.RWMutexm     map[string]muxEntryhosts bool // whether any patterns contain hostnames
}type muxEntry struct {explicit boolh        Handlerpattern  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         = iotaPOSTPUTDELETECONNECTIBNGHEADOPTIONSPATCHTRACE
)

    看完上面常量的设置,想必读者已经知道了我的意思,e.g:array[0]表示GET方法下所有的接口的集合,array[1]表示POST方法下所有的接口的集合基本原理其实也简单,把Get方法下的所有的接口都存储到array[0]的值中,以此推理其他方法。原理简单,但是一个框架的设计必须高内聚低耦合,一个Web框架中路由分发是基础,在该此处上需要建立更多的功能,比如说过滤器等。在初期设计的时候必须保证要有可扩展性,所以笔者认为难点在于此。下面直接上代码,对应的代码有充分的注释。

package odserverimport ("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         = iotaPOSTPUTDELETECONNECTIBNGHEADOPTIONSPATCHTRACE
)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"的简析及自制简单路由框架

golang自定义路由控制实现(一)相关推荐

  1. laravel 控制器 中间件 传递数据_Laravel5 自定义路由中间件的使用步骤,太好用,珍藏了!...

    前言 Laravel5中我们处理request请求,中间会有很多环节.本文所说的中间件,位于路由和控制器之间,起到过滤和筛选请求的作用. 为什么不放到"表单验证"里呢? 因为有些请 ...

  2. 【GoWeb开发实战】Beego的路由控制

    Beego的路由控制 二.路由控制 web框架中,路由是重要的一环,对于beego的路由配置如何? 2.1 默认路由 让我们从入口文件main.go先分析起来吧: package mainimport ...

  3. 理解路由控制(路由策略、策略路由)

    文章目录 前言 控制网络流量可达性 路由策略 路由策略的应用方式 ACL应用 IP-Prefix List应用 Filter-Policy工具介绍 Route-Policy工具介绍 策略路由 Traf ...

  4. c# mvc html.beginform,asp.net-mvc – 使用Html.BeginForm()与自定义路由

    这是你一定知道的默认路由: routes.MapRoute( "Default",// Route name "{controller}/{action}/{id}&qu ...

  5. gin自定义路由日志的格式

    gin自定义路由日志的格式 默认的路由日志是这样的: [GIN-debug] POST /foo --> main.main.func1 (3 handlers) [GIN-debug] GET ...

  6. (chap4 IP协议) 路由控制( Routing)

    1. 定义 路由控制是指将分组数据发送到最终目标地址的功能. 1.1 . 多跳路由 路由器或主机在转发IP数据包时只指定下一个路由器或主机,.而不是将到最终目标地址为止的所有通路全都指定出来. Hop ...

  7. ASP.NET MVC 自定义路由中几个需要注意的小细节

    本文主要记录在ASP.NET MVC自定义路由时,一个需要注意的参数设置小细节. 举例来说,就是在访问 http://localhost/Home/About/arg1/arg2/arg3 这样的自定 ...

  8. 【nodejs笔记3】Express基本用法,和路由控制,和模板渲染ejs

    1. 路由控制的工作原理 //routes/index.js中的代码//访问主页时,调用ejs模板引擎,渲染index.ejs模板文件,生成静态页面,并显示在浏览器中.router.get('/', ...

  9. [ASP.NET MVC2 系列] ASP.NET MVC 之如何创建自定义路由约束

     [ASP.NET MVC2 系列]      [ASP.NET MVC2 系列] ASP.Net MVC教程之<在15分钟内用ASP.Net MVC创建一个电影数据库应用程序>      ...

最新文章

  1. 顺序表的删除(按位置删、头删、尾删)
  2. linux 快速删除大量/大文件
  3. ubuntu 电源按钮操作_Ubuntu电脑操作基础:桌面背景,屏保和电源
  4. 【HDU - 5977】Garden of Eden(树分治)
  5. sap crm button_正值SAP中国成立25周年之际,江苏金来奇智能科技SAPB1项目正式启动...
  6. 并发、并行、线程、进程与CPU基本概念
  7. 自适应高度表格_React实现自适应高度的lt;textareagt;
  8. 【Oracle】并行等待之PX Deq Credit: need buffer
  9. 小米终于开始对外输出了!
  10. charset参数 sqluldr2_linux下配置 oracle数据导出工具sqluldr2
  11. PHP 微信小程序 WebSocket MySQL Redis实现聊天功能
  12. token干什么用_什么是Token?Token有什么用处?为什么使用它?Token认证又是什么?...
  13. Chrome IE 中QQ快速登录失效
  14. VS2015编译MPC-HC源码
  15. 计算机中鼠标的设置,电脑中如何设置鼠标光标的移动速度
  16. 1000:从今天开始入坑C语言
  17. 总结一波 Redis 面试题,收藏起来!
  18. 音视频编解码基础知识(1)- 音视频编解码过程
  19. 新程序语言 Wyvern 将不同Web语言融合在一起
  20. python 截取视频片段

热门文章

  1. “注册编辑已被管理员停用”之解决办法
  2. 使用remix和matemask部署智能合约到以太坊测试网络
  3. JavaWeb(十)——jetty服务器、创建jsp项目、servlet生命周期及url的匹配规则
  4. JavaScript(四)——面向对象编程、BOM、DOM、表单验证、jQuery
  5. java ee 分页_【JavaEE】JavaEE分页实践
  6. 第三届“SLAM技术及应用”暑期学校视频分享(完整版)
  7. 生产过程中计算机软件的确认--简述医疗器械生产过程确认
  8. C语言数组清空的几种方法比较
  9. pythonsubprocess执行多条shell命令_python中subprocess批量执行linux命令
  10. python只能使用内置数据库_隐藏彩蛋:你知道python有一个内置的数据库吗?