HTTP背景、内容、框架设计与实现 | 青训营

105 阅读5分钟

HTTP协议背景

HTTP为超文本传输协议(Hypertext Transfer Protocal)的缩写。超文本的含义为除了基础的文本(text)数据,还包含图片(jpg、png等)、音频(MP3等)、视频(avi等)数据。该协议规定了这些数据的几大部分:

  1. 协议开始。数据从何处开始。
  2. 协议元数据。元数据指描述目标数据属性的一类数据,例如文件系统中的文件头等。
  3. 超文本。目标数据本体。
  4. 协议结束。数据从何处结束。

HTTP协议内容

作为一个应用层的通信协议,可以按请求和响应分为两部分,每一类中具体信息如下。

请求

请求行

请求行规定该请求的请求方法、请求URL、协议名称和版本号。

  1. 请求方法
  • GET。发送一个请求来取得服务器上的某一资源。
  • POST。向 url 指定的资源提交数据或附加新的数据。
  • PUT。put 方法用于对资源进行完整更新,且是幂等(重复执行保持稳定)的。跟 post 方法很像,也是向服务器提交数据,但是 put 方法指向了资源在服务器上的位置,而 post 方法没有。
  • DELETE。删除服务器上的某资源。
  • PATCH。用于对资源进行部分更新,是非幂等的。
  • HEAD。只请求页面的首部。
  • OPTIONS。options 方法用于获取当前 url 所支持的方法。如果请求成功,会有一个 allow 的头包含类似 getpost 这样的信息。
  • TRACE。沿着目标资源路径进行消息换回测试。
  • CONNECT。用来建立到给定URI标识的服务器的隧道。
  1. 请求URL(Universal Resource Locator)
    与主机host组成完整的请求URL,host通常用域名来表示以隐藏实际的IP地址(端口有许多默认的,如80/8080所以没啥好隐藏的)。域名通过域名解析系统DNS(Domain Name System)解析获取IP地址,包含迭代方式和递归方式。该URL字段用/来划分路由树的层数,如URL:editor/drafts/7265579369652830262中editor表示第一层中的一个节点,drafts表示第二层的一个节点。
  2. 协议名称与版本号
    协议名称即HTTP协议,版本号规定使用哪个版本的HTTP协议。

请求头

请求头用Key:Value的形式来表示所带的参数以及对应的值,Key与Value之间用:来间隔,不同的Key-Value对用换行符隔开。如接收语言Accept-Language: zh-CN、主机名Host、缓存Cookie等。

请求体

请求体同样用Key=Value的形式来表示所带的参数以及对应的值,但是Key和Value对之间用&隔开。如name=tom。

响应

响应行

响应行与请求行的不同之处在于不包含方法与URL信息,只包含协议名称、版本号、状态码及状态描述。如:

  1. 协议名称与版本信息 -- HTTP/1.1
  2. 状态码及状态描述 -- 200 OK 具体的状态码表示信息可以参考baike.baidu.com/item/HTTP/2…

响应头

格式同请求头,但是参数以及其对应的值与其不同。如返回响应体类型Content-Type(值为html/text)、Set-Cookie等。

响应体

真正所需的响应信息,如对API发送请求返回的JSON文件、服务器返回的网页HTML文件等。

HTTP框架设计与实现

HTTP框架可以分为五层,包括应用层(Application)、中间件层(Middleware)、路由层(Route)、编解码层(Codec)、运输层(Transport)。各层之下包括许多具体的组件,如下表格所示。

ApplicationMiddlewareRouteCodecTransport
ContextRecoveryAddWebsocketnetpoll
RequestCircuitbreakFindHTTP1
ResponseTimeoutRoute TreeQuicgo get
HandlerAccess logRoute GroupHTTP2

除了五层框架之外,还存在一些贯穿框架的通用组件:

  1. errors
  2. test
  3. timer
  4. bytesbufferpool
  5. log
  6. Trace
  7. Metrics

应用层设计

  • 可理解性
  • 简单性
  • 冗余性
  • 兼容性
  • 可测性
  • 可见性

中间件设计

  • 洋葱模型:
    • 日志
      • Metrics
        • Biz Handler(输入Request输出Response)

适用场景:

  1. 日志记录
  2. 性能统计
  3. 安全控制
  4. 事务处理
  5. 异常处理

路由设计

  • 静态路由: /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池,将单独的上下文变为多个上下文组成的池,具有提高内存复用、性能等优势,但也带来了额外的复位、差错处理逻辑等。