你需要知道的 HTTP 协议
小麦2024年08月09日1757 字
HTTP 协议是连接世界的桥梁,
也是人们打开互联网大门的钥匙,
它对于前端的重要性是毫无疑问的。
由于 HTTP 协议内容众多,几分钟视频无法尽善尽美。因此,本期视频只介绍 HTTP 协议中最为重要的部分,以及它在大型客户端应用中的变体。
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 来实现加密传输。除了 HTTP/3,TLS 在其他版本中并不是强制要求的。
可以看到,每一代协议升级,都是围绕性能和安全性展开的。
HTTP 协议大体上是一种问答形式,客户端发出请求,服务器处理请求,然后再给出响应。无论是 HTML 文档,还是图片、视频等资源都是通过这种问答来传输的。
服务器会根据不同场景返回不同的响应码,具体可以参照这张表格。
只需要记住 2 开头表示成功处理,
3 开头表示重定向,
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.ajax、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 协议能带来更强大的功能。
本期内容只是简要介绍了 HTTP 协议本身,更多内容我们会在之后的视频中一一展开。如果这期视频对你有帮助,记得点个赞,我是小麦,我们下期不见不散。