# 超文本传输协议 HTTP
超文本 HyperText
HTTP 虽然叫传输协议,但它实际上工作在 TCP/IP 协议的应用层,底层的数据传输由 TCP 或 UDP 负责。
HTTP 协议发展至今已有多个版本,最常用的是 HTTP/1.1,HTTP/2 和 HTTP/3。
目前 HTTP/1.1 依然被广泛使用。
HTTP/2 引入了多路复用、二进制帧层、头部压缩等特性,提升了不少传输性能。
HTTP/3 基于 QUIC 协议使用 UDP 作为传输层,进一步降低了连接延迟和提升了传输性能。
值得注意的是,HTTPS 是 HTTP 的加密安全版本,它在原始 HTTP 协议的基础上,加盖了一层 SSL/TLS 来实现加密传输
HTTPSecure
除了 HTTP/3,TLS 在其他版本中并不是强制要求的。
可以看到,每一代协议升级,都是围绕性能和安全性展开的。

HTTP 协议大体上是一种问答形式,客户端发出请求,服务器处理请求,然后再给出响应。
服务器会根据不同场景返回不同的响应码。
2XX 表示成功处理,3XX 表示重定向,4 开头表示客户端错误,5 开头表示服务端错误
在请求和响应报文中,除了请求方法和响应码外,最值得关注的就是请求头和响应头。
比如:
用于请求上下文的 Host、Referer、User-Agent
用于响应上下文的 Allow、Server
用于缓存的 Cache-Control、Last-Modified/Last-Modified-Since 和 ETag/If-NoneMatch
用于 Cookie 的 Cookie 和 Set-Cookie
用于安全的 X-Frame-Options、Strict-Transport-Security (HSTS)、Content-Security-Policy (CSP)
用于跨域控制 (CORS) 的 Origin 和 Access-Control-* 一套
用于描述消息主体的 Content-* 一套

浏览器加载资源会使用 HTTP 协议,前端与服务端的异步请求通常也通过 HTTP 协议完成。
最早我们会通过 XMLHttpRequest (XHR),在浏览器中发起一个异步请求,后来许多第三方库基于它做了功能扩展,比如 jQuery、ajx、superagent 和 axios 等,直到出现了新的 Fetch 标准。
虽然 API 都长得一样,但 Fetch 标准在不同环境下有不同的实现,比如 Node.js 环境下的 fetch 是基于 Undici 实现的,而在边缘运行时(Edge Runtime)中,Fetch API 也会依据平台有所不同,因此,在现代前端,应尽可能使用 Fetch API 或其封装库来管理异步请求。
下面使用 Fetch API 和 Node.js 原生 http 模块,举例说明 Content-Type 是如何工作的,请求代码和报文是这样的:

对应的服务端处理代码和响应报文是这样的:

需要注意的是,请求头和响应头中的 Content-Type 表示消息主体的数据类型,它可以是 JSON、Form,也可以是其他任何 MIME 类型,不同的类型就要有不同的处理程序。
在这个例子中,客户端发送了一段 JSON 类型的数据,服务端应通过 JSON parse 处理,然后响应了一段纯文本类型,客户端应通过 text () 方法处理它。
这是一个易错点,前端使用第三方库时默认为 JSON 请求,而服务端默认以 Form 处理时,会百思不得其解为什么我处理不了你的请求,原因就是没有理解 Content-Type 的含义。
在不同的场景和环境下,调试 HTTP 有不同的方法。
- 最常见的当然是使用浏览器开发者工具,比如在 Chrome DevTools 的 Network 选项卡下,可以看到非常详细的 HTTP 请求和响应信息。
- 有时候只想快速看看服务端的响应情况,则可以通过 cURL 等命令行工具完成。
- 在针对 API 测试的场景下,可以通过 Postman 等自动化工具来批量测试。
- 而要调试移动设备内的 HTTPS,则需要安装信任证书以及通过网络代理工具来实现。
- 对于远程或是生产环境,则更多是通过抓包和分析服务端日志来完成
HTTP 的功能很强大,它足够满足大多数应用场景。但在大型客户端应用中,为了更高效和安全的传输数据,同时兼容 HTTP 协议,会有一些变化。
我们应该知道,不是所有的客户端环境都支持先进的 HTTP/2 或 HTTP/3,原始 HTTP 协议在更复杂的高并发场景下,会不够高效和稳定。
因此,大型技术基建通常会设计一层无线网关(Gateway),并对 HTTP 协议进行定制。

增加登录验证、请求跟踪、监控、限流等功能。而前端代码通过远程调用(RPC)的方式,而非直接使用原始 HTTP
以 bilibili 客户端为例,前端发起一个 grpc 请求至 gateway 网关,同时发送了多个自定义请求头,比如 x-bili-mid 表示当前用户,x-bili-trace-id 用于链路日志跟踪,x-bili-device-bin 表示设备信息等等。
在服务端的响应头中,Content-Type 表示这是一个 grpc 响应,x-bili-trace-id 用于日志跟踪等,可以看到,相比浏览器中的 HTTP,在客户端中的 HTTP 会更复杂,定制化的 HTTP 协议能带来更强大的功能。