一.分层设计
HTTP框架分层设计特点是专注性、扩展性、复用性等。如果按照OSI七层网络模型可以分为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层,按照TCP/IP四层概念模型分为应用层、传输层、网络层、数据链路层。
分层设计高内聚、低耦合、易复用、高扩展性。一个切实可行的复杂系统势必是从一个切实可行的简单系统发展而来的。从头开始设计的复杂系统根本不切实可行,无法修修补补让它切实可行。你必须由一个切实可行的简单系统重新开始。接下来分别对每一层进行分析。
1.应用层设计
提供合理的API。API需要可理解性:如 ctx.Body 0,ctx.GetBody (),不要用 ctx. BodyA ()。API尽量简单性: 如 ctx.Request.Header.Peek(key)/ctx. GetHeader (key)。
2.中间件设计
中间件需求:配合 Handler 实现一个完整的请求处理生命周期;拥有预处理逻辑与后处理逻辑;可以注册多中间件;对上层模块用户逻辑模块易用。洋葱模型主要在于核心逻辑与通用逻辑分离,适用于日志记录、性能统计、安全控制、事务处理、异常处理。
例:打印每个request和response
func main(){
h := server.New( )
h.POST("/login", func(c context.Context,ctx *app.RequestContext){
// print request
logs.Infof("Received awRequest: %s",ctx.Request.RawRequest())
// some biz logic
ctx.JSON(200,"0K")
// print response
logs.Infof( "Send RawResponse: s",ctx.Response.RawResponse())
})
h.POST("/logout", func(c context,Context, ctx *app.RequestContext){
// print request
logs.Infof("Received RawRequest: %s",ctx.Request.RawRequest())
// some biz logic
ctx.JSON(200,"0K")
// print response
logs.Infof("Send RawResponse: %s",ctx.Response.RawResponse( ))
})
h.Spin( )
}
1.既然要实现预处理和后处理,那这个就很像调用了一个函数。
func Middleware( some param) {
// some logic for pre-handle
...
nextMiddleware() / bizLogic( )
// some logic after-handle
...
}
2.路由上可以注册多 Middleware,同时也可以满足请求级别有效只需要将 Middleware 设计为和业务和 Handler 相同即可。
func Middleware( some param) {
// some logic for pre-handle
...
Next()
// some logic after-handle
...
}
3.用户如果不主动调用下一个处理函数,可以在任何场景下使用index保证递增。
func (ctx *RequestContext) Next() {
ctx.index++
for ctx.index < int8(len(ctx.handlers)) {
ctx.handlers[ctx.index]()
ctx.index++
}
}
4.出现异常停止调用。
func (ctx *RequestContext) Abort() {
ctx.index = IndexMax
}
中间件设计的调用链如图:
适用场景 1.不调用 Next:初始化逻辑且不需要在同一调用栈。2.调用 Next:后处理逻辑或需要在同一调用栈上。
3.路由设计
使用map[string]handlers,如:/a/b/c、/a/b/d/a/:id/c、/*all。使用前缀匹配树方法,如/a/b/c、/a/b/d。匹配HTTP方法可以使用路由映射表Map层Method(String),由前缀树和头结点组成,外层Map根据method进行筛选。如果要添加多处理函数,在每个节点上使用一个list存储handler。
node struct {
prefix string
parent *node
children children
handlers app.HandlersChain
...
}
设计要点:1.明确需求:考虑清楚要解决什么问题、有哪些需求业界调研:业界都有哪些解决方案可供参考3.方案权衡: 思考不同方案的取舍方案评审: 相关同学对不同方案做评审4.确定开发:确定最合适的方案进行开发5.确定开发: 确定最合适的方案进行开发
4.协议层设计
抽象出合适的接口:
type Server interface {
Serve(c context.Context, conn network.Conn) error
}
5.网络层设计
BIO网络模型,用户管理buffer
type Conn interface {
Read(b []byte) (n int, err error)
Write(b []byte) (n int, err error)
...
}
NIO网络模型,网络库管理buffer
type Reader interface {
Peek(n int) ([]byte, error)
...
}
type Writer interface {
Malloc(n int) (buf []byte, err error)
Flush() error
...
}
二.总结
API设计:可理解性、简单性
中间件设计:洋葱模型
路由设计:前缀匹配树
协议层设计: 抽象出合适的接口
网络层设计: 网络模型