这是我参与「第三届青训营 -后端场」笔记创作活动的的第 8 篇笔记
HTTP协议
定义
HTTP:超文本传输协议(Hypertext Transfer Protocol),能够附加如图片、链接、视频等这样的文本叫做超文本
协议明确了传播的消息的边界(开始点和结束点)、记录了消息数据、类型
组成
请求行:包含方法名、URL、协议版本
状态行:包含协议版本、状态码、状态码描述
POST /sis HTTP/1.1
元数据(请求头/响应头):协议相关数据
Who: Alex
Content-Type: text/plain
Host: 127.0.0.1:8888
Content-Length: 28
请求体/响应体:业务相关数据
Hello world
请求流程
不足与发展
HTTP1:队头阻塞、传输效率低、明文传输不安全
HTTP2:多路复用、头部压缩、二进制协议
QUIC:基于UDP实现、解决队头阻塞、加密减少握手次数、支持快速启动
HTTP框架的设计与实现
应用层设计
提供合理的API
- 可理解性
- 简单性
- 冗余性
- 兼容性
- 可测性
- 可见性
中间件层设计
中间件层的需求
- 配合Handler实现一个完整的请求处理生命周期
- 拥有预处理逻辑和后处理逻辑
- 可以注册多中间件
- 对上层模块用户逻辑模块易用
洋葱模型
适用场景:日志记录、性能统计、安全控制、事务处理、异常处理
路由层设计
框架路由实际上就是为URL匹配对应的处理函数
- 静态路由:/a/b/c、/a/b/d
- 参数路由:/a:id/c、/*all
- 路由修复:/a/b <-> 、/a/b/
- 冲突路由以及优先级:/a/b、/:id/c
- 匹配HTTP方法类型
- 多处理函数:方便添加中间件
实现方案
- map映射,但是只能处理静态路由
- 前缀匹配树
如何匹配http方法?
协议层设计
- Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter(不要把Context放在结构体里面,而是应该当作需要他的函数的第一个参数传入函数中)
- 需要在连接上写数据
传输层设计
- BIO:读数据的时候会先阻塞,直到读到足够的数据再进行处理
- NIO:监听数据,当存在足够的数据才读取,不会阻塞
网路层设计
go net网络库
框架优化
针对网络库的优化
go net——流式友好、小包性能好
- 存下全部的Header
- 减少系统调用次数
- 能够复用内存
- 能够多次读
netpoll——大包性能好,时延低
- 存下全部的Header
- 拷贝出完整的body
针对
Headers解析
- 找到Header Line变价:\r\n——先找到\n再看它前一个是不是\r
针对协议相关的Header快速解析
- 通过Header key首字母快速筛除掉完全不可能的key
- 解析对应的value到独立字段
- 使用byte slice管理对应header存储,方便复用
Header key规范化 aaa-bbb -> Aaa-Bbb:使用表映射的方式将字节存储到map中