真实面经题目 · 原创解析
HTTP 如何判断一个包读完了?
这题考 HTTP 报文解析和 TCP 字节流边界,关键是说明不能靠一次 recv 或 TCP 包判断 HTTP 是否读完。
真实面经题目 · 原创解析
这题考 HTTP 报文解析和 TCP 字节流边界,关键是说明不能靠一次 recv 或 TCP 包判断 HTTP 是否读完。
HTTP 跑在 TCP 上时,TCP 只提供连续字节流,不保留应用层报文边界,所以不能靠一次 read、recv 或一个 TCP 包判断读完。HTTP/1.x 先读起始行和 Header,遇到空行后根据规则判断 Body:有 Content-Length 就读指定字节数;Transfer-Encoding: chunked 就按 chunk size 逐块读到 0 长度块;某些响应可通过连接关闭结束;HEAD、1xx、204、304 等场景没有响应体或有特殊规则。HTTP/2 则依靠二进制帧头长度和 END_STREAM 标志。
发送方一次 write 可能被拆成多次接收,多个 HTTP 报文也可能在一次 read 中被读到。应用层必须维护缓冲区并按协议解析,不能把网络包当报文。
HTTP/1.x 先解析起始行和 Header,Header 与 Body 之间用空行分隔。只有 Header 读完整后,才能根据方法、状态码和头字段决定是否还有 Body 以及读多长。
Content-Length 明确声明 Body 字节数,解析器读满这个长度才认为消息体结束。若连接复用,后面的字节可能已经属于下一个响应或请求,不能多读后丢弃。
chunked 传输把 Body 切成多个块,每块先给十六进制长度,最后以 0 长度块结束。没有长度信息的老式响应可能以连接关闭作为结束,但这会影响连接复用。
HEAD 请求的响应、1xx、204、304 通常没有消息体;CONNECT、升级协议和 HTTP/2/3 又有不同边界机制。答题时能补这些边界,会比只背 Content-Length 更完整。
TCP 是字节流协议,网络分片、合并、缓冲都会改变应用读到的边界,应用必须按 HTTP 协议字段解析。
规范上 Transfer-Encoding 优先且这类组合容易引发请求走私风险,服务端应严格校验并拒绝异常报文。
多读到的字节要留在连接缓冲区,作为下一个报文继续解析,不能当作当前消息体的一部分丢掉。
HTTP/2 使用二进制帧,每个帧头带长度,流结束由 END_STREAM 标志表示,不再依赖文本 Header 后的 Content-Length 规则来分帧。