0. 为什么大家都用http

introduction

你比如你今天想上b站看鬼畜, 然后你就在地址栏上输入了 bilibili.com/v/kichiku 然后回车, 然后我们都知道浏览器把这个请求发出去了, 好, 浏览器是如何把一个字符串翻译成一个 http 请求的? 这种... 哼哼... 有点愚蠢的问题怎么能难得倒我呢, 让我抓个包我立刻就知道了(flag=true), 那么既然 HTTP协议基于TCP/IP协议包装而成, 那么我们自然要先填充TCP/IP部分:

  • IP报文填充: 通过DNS协议/DNS缓存拿到对端IP, 发现不在本局域网内, 填充上本机IP以及对端IP, (并在数据链路层里) 填充上本机Mac以及路由器Mac

  • TCP报文填充: 随机分配一个本机端口信息, 以及对端口信息80, 依次填写ACK序号, TCP控制位(ACK=1), 窗口大小, 以及紧急事件位设置为0

在这个过程完成了以后我们可以开始观察http协议的模式了

  1. HTTP请求 / 长啥样

  2. HTTP响应 / 长啥样

  3. 我们为什么需要http协议

http protocol - 请求结构

话说在tcp眼里看来, http协议的内容都只是tcp的正文部分, 同样的在ip眼里看来, 你tcp也只是我ip的正文部分而已, 所以我们说这种行为像是一种"包装". 那么既然是tcp, tcp是没有包长度的说法的, 这时候就必须要考虑到如何读包的问题 (也就是粘包问题). 常见的方法有两种:

  • 在报头第一个位置里写明包长度, MongoDB协议用的这种

  • 有一个明确的终止符, http用的就是这种

GET / HTTP/1.1        \r\n  # HTTP报头, 包含方法名, path, 协议版本
Host: localhost:8001  \r\n  # HTTP-Host
header1: v1           \r\n  # 若干个HTTP-Header
header2: v2           \r\n
...                   \r\n
\r\n                        # 使用一个\r\n作为终止

http 响应长啥样

对于一个带有body的请求, 则是把body放在终止符后面, 那么既然body并不用\r\n作为终止符, 它的大小怎么确定呢? 它的大小由header里的一个名为Content-Length的字段决定, 如下图所示, body的长度显示为45, Content-Length里标注出来了

body看完以后我们看看响应报文长啥样, 其实基本也没啥不同: 出现了两个header用于描述body类型, body长度以及编码方式, 最后没有http方法, 值得注意的是这两点并不是响应报文特有的, 任何带body的http报文(比如psot请求)都会出现这两个header, 而且也曾经出现过http请求也没有方法的.

为什么大家都在用http协议

我觉得一个比较有价值的问题是, 为什么http协议被如此广泛的使用, 已经到了满天飞的地步, 为什么呢? 或者换一种问法: 如果今天只用tcp做网页, 怎样? 有什么问题? ok 既然你用了tcp, 那么你就要制定协议格式, 来保证如何从tcp里读包, 你或是写包长度或者就直接跟http一样用\r\n当分隔符.

这就意味着你一定要在上面包装出一个自己的协议, 那为什么不能是http呢? 事实上没有人能裸用tcp, 即使是最接近裸tcp效果的, 有着著名的"实时返回效果"的websocket, 也需要自己制定一套协议规则

或许你会想, 既然tcp不好读, 那咱用udp? 然后再附加一套咱们自己的保证稳定传输的机制不就好了吗? 你说的没错, 确实有人这么干了已经, 那就是 http3.

Last updated

Was this helpful?