frame of golang http
基于net/http框架个部分总结
适用框架:golf、echo、gin、dotweb、iris、beego。
golang大部分框架都是基于标准库net/http包现实,fasthttp框架就是自己解析http协议,从新实现了类似net/http包的功能。
通常框架包含的部分有Application、Context、Request、Response、Router、Middleware、Logger、Binder、Render、View、Session、Cache这些部分,一般都是有部分,不过前五个是一定存在。
以下列出了各框架主要部分定义位置:
golf
echo
gin
dotweb
iris
beego
Application
Context
Request
http.Request
http.Request
http.Request
http.Request
Response
http.ResponseWriter
Router
Middleware
Logger
Binder
Render
View
Session
Cache
Websocket
MVC
源码解析:golf
Application
application一般都是框架的主体,通常XXX框架的主体叫做XXX,当然也有叫App、Application、Server的实现,具体情况不你一致,不过一般都是叫XXX,源码就是XXX.go。
这部分一般都会实现两个方法Start() error
和ServeHTTP(ResponseWriter, *Request)
Start() error
一般是框架的启动函数,用来启动服务,名称可能会是Run,创建一个http.Server对象,设置TLS相关等配置,然后启动服务,当然也会出现Shutdown方法。
ServeHTTP(ResponseWriter, *Request)
函数实现http.Handler接口,一般框架都是使用http.Server对象来启动的服务,所以需要实现此方法。
此本方法大概就三步,Init、Handle、Release。
第一步Init,一般就是初始化Context对象,其中包括Request和Response的初始化Reset,使用ResponseWriter
和*Request
对象来初始化,通常会使用Sync.Pool来回收释放减少GC。
第二步Handle,通常就是框架处理请求,其中一定包含路由处理,使用路由匹配出对应的Handler来处理当前请求。
第三步释放Context等对象。
简单实现:
Context
Context包含Request和Response两部分,Request部分是请求,Response是响应。Context的各种方法基本都是围绕Request和Response来实现来,通常就是各种请求信息的获取和写入的封装。
简单实现:
RequestReader & ResponseWriter
http协议解析文档。
实现RequestReader和ResponseWriter接口。
根据http协议请求报文和响应报文RequestReader和ResponseWriter大概定义如下:
RequestReader用于读取http协议请求的请求行(Request Line)、请求头(Request Header)、body。
ResponseWriter用于返回http写法响应的状态行(Statue Line)、响应头(Response Header)、body这些数据。
在实际过程还会加入net.Conn对象的tcp连接信息。
通常net/http库下的RequestReader和ResponseWriter定义为http.Request和http.ResponseWriter,请求是一个结构体,拥有请求信息,不同情况下可能会有不同封装,或者直接使用net/http定义的读写对象。
Router
Router是请求匹配的路由,并不复杂,但是每个框架都是必备的。
通常实现两个方法Match和RegisterFunc,给路由器注册新路由,匹配一个请求的路由,然后处理请求。
定义一个非常非常简单的路由器。
这个简单路由仅支持了rsetful风格,连通配符匹配都没有实现;但是体现了路由器的作用,输出一个参数,返回一个对应的处理者。
至于如何对应一个处理路由,就是路由器规则的设定了;例如通配符、参数、正则、数据校验等功能。
Middleware
通常是多个Handler函数组合,在handler之前之后增一些处理函数。
echo
echo中间件使用装饰器模式。
echo中间件使用HandlerFunc进行一层层装饰,最后返回一个HandlerFunc处理Context
gin
gin在路由注册的会中间件和route合并成一个handlers对象,然后httprouter返回匹配返回handlrs,在context reset时设置ctx的handlers为路由匹配出现的,handlers是一个HanderFunc数组,Next方法执行下一个索引的HandlerFunc,如果在一个HandlerFunc中使用ctx.Next()就先将后续的HandlerFunc执行,后续执行完才会继续那个HandlerFunc,调用ctx.End() 执行索引直接修改为最大值,应该是64以上,毕竟Handlers合并时的数据长度限制是64,执行索引成最大值了,那么后面就没有HandlerFunc,就完整了一次ctx的处理。
echo通过路由匹配返回一个[]HandlerFunc对象,并保存到Context里面,执行时按ctx.index一个个执行。
如果HandlerFunc里面调用ctx.Next(),就会提前将后序HandlerFunc执行,返回执行ctx.Next()后的内容,可以简单的指定调用顺序,ctx.Next()之前的在Handler前执行,ctx.Next()之后的在Handler后执行。
Context.handlers存储本次请求所有HandlerFunc,然后使用c.index标记当然处理中HandlerFunc,
iris
Beego
Logger
框架基础日志接口
Binder & Render & View
Binder的作用以各种格式方法解析Request请求数据,然后赋值给一个interface{}。
Render的作用和Binder相反,会把数据安装选择的格式序列化,然后写回给Response部分。
View和Render的区别是Render输入的数据,View是使用对应的模板渲染引擎渲染html页面。
Session & Cache
seesion是一种服务端数据存储方案
持久化
Cache持久化就需要把数据存到其他地方,避免程序关闭时缓存丢失。
存储介质一般各种DB、file等都可以,实现一般都是下面几步操作。
1、getid:从请求读取sessionid。
2、initSession:用sessionid再存储中取得对应的数据,一般底层就是[]byte
3、newSession:反序列化成一个map[string]interface{}这样类似结构Session对象。
4、Set and Get:用户对Session对象各种读写操作。
5、Release:将Session对象序列化成[]byte,然后写会到存储。
存储介质
内存:使用简单,供测试使用,无法持久化。
文件:存储简单。
sqlite:和文件差不多,使用sql方式操作。
mysql等:数据共享、数据库持久化。
redis:数据共享、协议对缓存支持好。
memcache:协议简单、方法少、效率好。
etcd:少量数据缓存,可用性高。
golang session
一组核心的session接口定义。
Provider.SessionRead(sid string) (Session, error)
用sid来从Provider读取一个Session返回,sid就是sessionid一般存储与cookie中,也可以使用url参数值,Session对象会更具sid从对应存储中读取数据,然后将数据反序列化来初始化Session对象。
Session.Release(w http.ResponseWriter)
从名称上是释放这个Seesion,但是一般实际作用是将对应Session对象序列化,然后存储到对应的存储实现中,如果只是读取Session可以不Release。
简单的Seession实现可以使用一个map,那么你的操作就是操作这个map。
在初始化Session对象的时候,使用sessionId去存储里面取数据,数据不在内存中,你们通常不是map,比较常用的是[]byte,例如memcache就是[]byte,[]byte可以map之间就需要序列化和反序列化了。
在初始化时,从存储读取[]map,反序列化成一个map,然后返回给用户操作;最后释放Session对象时,就要将map序列化成[]byte,然后再回写到存储之中,保存新修改的数据。
Beego.Seesion
使用例子:
在beego.session中Store就是一个Session。
1、SessionStart定义在session.go#L193,用户获取Store对象,在194line获取sessionid,在200line用sid从存储读取sessio.Store对象。
2、memcache存储在[124line][4]定义SessionRead函数来初始化对象。
3、其中在[sess_memcache.go#L139][5]使用memcache获取的数据,使用gob编码反序列化生成了map[interface{}]interface{}类型的值kv,然后144line把kv赋值给了store。
4、在57、65 [set&get][6]操作的rs.values,就是第三部序列化生成的对象。
5、最后释放store对象,定义在[94line][7],先把rs.values使用gob编码序列化成[]byte,然后使用memcache的set方法存储到memcache里面了,完成了持久化存储。
源码分析总结:
session在多线程读写是不安全的,数据可能冲突,init和release中间不要有耗时操作,参考其他思路一样,暂无解决方案,实现读写对存储压力大。
对session只读就不用释放session,只读释放是无效操作,因为set值和原值一样。
beego.session可以适配一个beego.cache的后端,实现模块复用,不过也多封装了一层。
golang cache
实现Get and Set接口的一种实现。
简单实现
这组接口[sync.Map][]简化出来的,这种简单的实现了get&set操作,数据存储于内存中,map类型也可以直接实现存储。
复杂实现
封装各种DB存储实现接口即可,这样就可以实现共享缓存和持久化存储。
Websocket
协议见文档
Last updated
Was this helpful?