golang自定义路由控制实现(一)

栏目: Go · 发布时间: 5年前

内容简介:由于本人之前一直是Java Coder,在Java web开发中其实大家都很依赖框架,所以当在学习Golang的时候,自己便想着在Go开发中脱离框架,自己动手造框架来练习。通过学习借鉴Java的思想还有部分框架的源码,在golang上面进行实现,从而达到对Java和Golang的同时学习目的,这就很美滋滋了。     Golang中http的设计非常轻量,又兼具很高的扩展性,初学者都可以轻易的设计出自定义的路由功能,使用上十分简单(这里……来吐槽一下Java的Servlet,虽然我也对Java爱得深沉),下

    由于本人之前一直是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框架中路由分发是基础,在该此处上需要建立更多的功能,比如说过滤器等。在初期设计的时候必须保证要有可扩展性,所以笔者认为难点在于此。下面直接上代码,对应的代码有充分的注释。

/**
odserver.go
*/
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})
}

复制代码
/**
router.go
*/
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"的简析及自制简单路由框架

​ 作者:plz叫我红领巾

​ 出处: juejin.im/post/5ce244…

本博客欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Host Your Web Site In The Cloud

Host Your Web Site In The Cloud

Jeff Barr / SitePoint / 2010-9-28 / USD 39.95

Host Your Web Site On The Cloud is the OFFICIAL step-by-step guide to this revolutionary approach to hosting and managing your websites and applications, authored by Amazon's very own Jeffrey Barr. "H......一起来看看 《Host Your Web Site In The Cloud》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试