HTTP协议背景
HTTP为超文本传输协议(Hypertext Transfer Protocal)的缩写。超文本的含义为除了基础的文本(text)数据,还包含图片(jpg、png等)、音频(MP3等)、视频(avi等)数据。该协议规定了这些数据的几大部分:
- 协议开始。数据从何处开始。
- 协议元数据。元数据指描述目标数据属性的一类数据,例如文件系统中的文件头等。
- 超文本。目标数据本体。
- 协议结束。数据从何处结束。
HTTP协议内容
作为一个应用层的通信协议,可以按请求和响应分为两部分,每一类中具体信息如下。
请求
请求行
请求行规定该请求的请求方法、请求URL、协议名称和版本号。
- 请求方法
- GET。发送一个请求来取得服务器上的某一资源。
- POST。向
url指定的资源提交数据或附加新的数据。 - PUT。
put方法用于对资源进行完整更新,且是幂等(重复执行保持稳定)的。跟post方法很像,也是向服务器提交数据,但是put方法指向了资源在服务器上的位置,而post方法没有。 - DELETE。删除服务器上的某资源。
- PATCH。用于对资源进行部分更新,是非幂等的。
- HEAD。只请求页面的首部。
- OPTIONS。
options方法用于获取当前url所支持的方法。如果请求成功,会有一个allow的头包含类似get、post这样的信息。 - TRACE。沿着目标资源路径进行消息换回测试。
- CONNECT。用来建立到给定URI标识的服务器的隧道。
- 请求URL(Universal Resource Locator)
与主机host组成完整的请求URL,host通常用域名来表示以隐藏实际的IP地址(端口有许多默认的,如80/8080所以没啥好隐藏的)。域名通过域名解析系统DNS(Domain Name System)解析获取IP地址,包含迭代方式和递归方式。该URL字段用/来划分路由树的层数,如URL:editor/drafts/7265579369652830262中editor表示第一层中的一个节点,drafts表示第二层的一个节点。 - 协议名称与版本号
协议名称即HTTP协议,版本号规定使用哪个版本的HTTP协议。
请求头
请求头用Key:Value的形式来表示所带的参数以及对应的值,Key与Value之间用:来间隔,不同的Key-Value对用换行符隔开。如接收语言Accept-Language: zh-CN、主机名Host、缓存Cookie等。
请求体
请求体同样用Key=Value的形式来表示所带的参数以及对应的值,但是Key和Value对之间用&隔开。如name=tom。
响应
响应行
响应行与请求行的不同之处在于不包含方法与URL信息,只包含协议名称、版本号、状态码及状态描述。如:
- 协议名称与版本信息 -- HTTP/1.1
- 状态码及状态描述 -- 200 OK 具体的状态码表示信息可以参考baike.baidu.com/item/HTTP/2…
响应头
格式同请求头,但是参数以及其对应的值与其不同。如返回响应体类型Content-Type(值为html/text)、Set-Cookie等。
响应体
真正所需的响应信息,如对API发送请求返回的JSON文件、服务器返回的网页HTML文件等。
HTTP框架设计与实现
HTTP框架可以分为五层,包括应用层(Application)、中间件层(Middleware)、路由层(Route)、编解码层(Codec)、运输层(Transport)。各层之下包括许多具体的组件,如下表格所示。
| Application | Middleware | Route | Codec | Transport |
|---|---|---|---|---|
| Context | Recovery | Add | Websocket | netpoll |
| Request | Circuitbreak | Find | HTTP1 | |
| Response | Timeout | Route Tree | Quic | go get |
| Handler | Access log | Route Group | HTTP2 |
除了五层框架之外,还存在一些贯穿框架的通用组件:
- errors
- test
- timer
- bytesbufferpool
- log
- Trace
- Metrics
应用层设计
- 可理解性
- 简单性
- 冗余性
- 兼容性
- 可测性
- 可见性
中间件设计
- 洋葱模型:
-
- 日志
-
-
- Metrics
-
-
-
-
- Biz Handler(输入Request输出Response)
-
-
适用场景:
- 日志记录
- 性能统计
- 安全控制
- 事务处理
- 异常处理
路由设计
- 静态路由: /a/b/c、/a/b/d
- 参数路由: /a/:id/c (/a/b/c,/a/d/c)、/*all
- 路由修复: /a/b <-> /a/b/
- 冲突路由与优先级: /a/b、/:id/c
- 匹配HTTP方法
协议层设计
# 使用合适的接口
type Server interface {
Serve(c context.Context, conn network.Conn) error
}
网络层设计
- BIO。如go net库,一个请求到达时会创建协程执行服务。
- NIO。如netpoll高性能非阻塞网络库,使用请求池实现拿出与处理请求。
HTTP优化
网络库优化
- go net。流式友好,小包性能高。
- netpoll。中大包性能高,时延低。
协议优化
- Headers解析可以使用SIMD(Single Instruction Multiple Data)技术,通过很少的指令就可以解析多个数据,大大减少了所需时间。
- 针对Key首字母、大小写等使用特定方式加速,但都存在tradeoff。
- RequestContext池,将单独的上下文变为多个上下文组成的池,具有提高内存复用、性能等优势,但也带来了额外的复位、差错处理逻辑等。