这是我参与「第三届青训营 -后端场」笔记创作活动的的第13篇笔记. HyperText Transfer Protocal
- PATCH和PUT方法的区别? PATCH对应部分更新,PUT的语义是完整更新,具有幂等性。
package main
import (
"context"
//"code.byted.org/middleware/hertz/pkg/app"
//"code.byted.org/middleware/hertz/pkg/app/server"
)
func main(){
h:=server.New()
h.POST("/sis",func(c context.Context,ctx *app.RequestContext){
ctx.Data(200,"text/plain;charset=utf-8",[]byte("OK"))
})
h.Spin()
}
业务层->服务治理层/中间件层->路由层->协议编解码层->传输层
Http1
- 对头阻塞,基于tcp,后序分片需要等待前面分片的结束,否则会一直等待
- 传输效率低 不支持多路复用
- 明文传输,不安全
http2
- 多路复用
- 头部压缩
- 二进制协议 解析高效
QUIC
- 基于UDP
- 解决队头阻塞
- 优化加密算法,减少握手次数
- 快速启动
分层设计
应用层
- 提供合理api
- 可理解性
- 简单性
- 避免冗余性
- 兼容性
- 可测性
- 可见性
中间件层
- 需求
- 配合Handler实现完整的请求处理生命周期
- 预处理和后处理逻辑
- 注册多中间件
- 对上层模块和用户模块易用
- 洋葱模型
- 日志记录
- 性能统计
- 安全控制
- 事务处理
- 异常处理 日志->Metrics->Biz Handler->Metrix->日志
func main(){
h:=server.New()
h.Use(func(c context.Context,ctx *app.RequestContext){
//print request
logs.Infof("Received RawRequest:%s",ctx.Request.RawRequest())
//next handler
ctx.Next(c)
//print response
logs.Infof("Second RawResponse:%s",ctx.Response.RawResponse())
})
h.POST("/login",func(c context.Context,ctx *app.RequestContext){
//some biz logic
ctx.JSON(200,"OK")
})
h.POST("/logout",func(c context.Context,ctx *app.RequestContext){
//some biz logic
ctx.JSON(200,"OK")
})
h.spin()
}
关于中间件的设计:
//1.需要实现预处理和后处理,类似于函数的调用
func Middleware(some param){
//pre-handle
//调用下一个处理函数。
Next()
//after-handle
}
//路由上可以注册多middleware,也可以满足请求级别有效。只需将midlleware设计为业务和handler相同即可
//2. 如果用户不主动的调用下一个处理函数
func (ctx *RequestContext) Next(){
ctx.index++
for ctx.index<int8(len(ctx.handlers)){
ctx.handlers[ctx.index]()
//任何场景下index递增
ctx.index++
}
}
//3. 如果调用过程出现了异常,想要停止,如何处理
func (ctx *RequestContext) Abort(){
//index设为最大值,直接跳出循环
ctx.index=IndexMax
}
那么,有没有其他方式来实现中间件?
路由设计
框架路由实际上是为URL匹配对应的处理函数。
协议层设计
- 不要把context写进struct,而是通过参数处理
- 在连接上读写数据
传输层设计
BIO
BLOCK
package main
go func(){
for {
conn,_:=listener.Accept()
go func(){
conn.Read(request)
...
conn.Write(response)
}
}
}
go/net是BIO
NIO
NON-BLOCKING
注册监听器。
go func(){
for{
readableConn,_ :=Monitor(conns)
for conn:=range radableConn{
go func(){
conn.Read(request)
...
conn.Write(response)
}
}
}
}
netpoll是NIO
网络库优化
go net的优化思路
- 存下全部Header
- 减少系统调用
- 复用内存
- 多次读
go net with bufio 绑定大小为4k的缓冲区
netpoll的优化思路 - 存下全部Header
- 拷贝完整的Body