支持多媒体、具有交互性、能够互相跳转的文本,被称为超文本(Hypertext),现代网页就是超文本的实例。而传输超文本的协议,被称为超文本传输协议(Hypertext Transfer Protocol, HTTP)。绝大部分网址的格式是 http(s)://domain/path,所以你发现了,HTTP 是现代互联网的基石协议
本文讨论 HTTP 请求与响应的结构

TCP 协议家族

HTTP 底层依赖了 TCP 协议, 本文不会详细探讨 TCP,你只需知道除了 HTTP 以外,基于 TCP 的协议还有 FTP(用于文件传输)、SMTP(邮件发送)、IMAP(邮件接收)、WebSocket(交互会话)、SSH(远程终端)、SMB(文件设备共享)、Postgresql(数据库)等等,都在各自领域发挥作用
这些协议对应的 url 格式也非常类似,只不过有些部分常常省略。例如 HTTP 协议的 user,password 一般不在 url ,而是在特有的请求头(Request Header)中

http://host:port/path?params
ws://host:port/path?params
ftp://user:password@host:port/path
postgres://user:password@host:port/database?params

HTTP 的结构

HTTP 的请求与响应总是成对出现。请求发起时,由客户端(浏览器)向服务器发送报文(message),该报文由请求行(request line)、请求头(request headers)、请求体(request body)组成。服务器处理请求后,返回响应,由状态行(status line)、响应头(response headers)、响应体(response body)组成
报文首行称为请求行/响应行,记录了最重要的元数据,请求头/响应头记录了其他重要的元数据,请求体/响应体则记录了传递数据的正文
如果你希望看到请求行、请求头,在浏览器的审查元素 ->网络下,选中某个请求,在右侧的“请求标头”处勾选原始
image.png
访问 www.baidu.com 得到的请求行和请求头如下

GET / HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: keep-alive
Cookie: ...
Host: www.baidu.com
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0
sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Microsoft Edge";v="128"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"

可以看到,请求行 GET / HTTP/1.1 记录了请求方法、路径、HTTP 版本,而请求头是类似 object 或 dict 的结构,记录了 Host 等元数据。我们将在之后讨论重要的请求头字段
响应行、响应头以类似的方式获取,例如

HTTP/1.1 200 OK
Connection: keep-alive
Content-Encoding: gzip
Content-Security-Policy: frame-ancestors 'self';
Content-Type: text/html; charset=utf-8
Date: Fri, 06 Sep 2024 13:04:39 GMT
Isprivate: 1
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: BWS/1.1
Set-Cookie: ...
Set-Cookie: ...
Traceid: 1725627879237967028215960242495075607159
X-Ua-Compatible: IE=Edge,chrome=1
X-Xss-Protection: 1;mode=block
Transfer-Encoding: chunked

响应行 HTTP/1.1 200 OK 记录了 HTTP 协议版本、状态码和状态消息,响应头同样也是 object 或 dict

请求方法

HTTP 协议约定了 GET、POST、PUT、DELETE 等请求方法,分别用于实现不同的功能,最常见的是前两种
GET 方法用于参数简单、同时不会产生副作用的操作,例如获取数据。GET 方法的参数常常以 http://host/path?arg1=v1&arg2=v2 的形式写在 url 中
POST 方法相对高级一些,允许将复杂参数放在 body 中发送,也允许触发服务端数据的变化。POST 最经典的用法是提交表单、上传文件,也常常代替 PUT、DELETE 方法用于更新、删除数据
以上只是约定,不会有任何真正的限制。你完全可以构建一个带 body 的 GET 请求,或用 GET 请求删除数据库的记录,但最好别这样
用户在浏览器输入 url 时,发出的都是 GET 请求。需要 POST 时,一般是通过 GET 取得 JS 代码,然后通过浏览器 JS 引擎执行代码内的请求。也就是说,浏览器内用户无法自主发起 POST 请求,只能遵循网站开发者的意图,通过点击交互按钮等方式借助 JS 代码发起
如果你使用 curl、wget 等命令行工具,或编程语言的 HTTP 接口(如 Python 的 requests 或 httpx,JS 的 fetch 或 axios),就可以完全自由地构造请求,包括请求方法,这在网络爬虫中很常见
另外,构造请求最常见的方式是专用软件,如 Postman、Apifox,适用于测试,比写代码方便很多

请求头字段

Host:请求的目标域名或 IP、端口
User-Agent

  • 简称 UA,标识发起请求的客户端软件,如操作系统、浏览器类型和版本
  • 浏览器是作为用户的代理者(agent)访问服务端资源的,这就是该字段名称的来源
  • 在互联网发展早期,不同浏览器差别很大,服务端可以通过 UA 返回不同的资源
  • 目前浏览器早已大同小异,许多浏览器为了兼容性把原本是别家浏览器的 UA 合在一起,全都放到请求头中
  • 目前 UA 最大的用处是区分桌面端和移动端、反爬虫

Referer

  • 表示当前请求的来源页面 url,常用于网站统计、防盗链、反爬虫
  • 如果来源 url 内包含了敏感信息,可能被该字段暴露
  • 为解决这个问题,可设定引用站点策略为 strict-origin-when-cross-origin,当请求在同一 host 时,携带完整 url;如果请求跨域,只携带 host
  • 设定方式很多,如,HTML 的 <meta> 标签、具体 <a> 标签的属性、HTTP 服务器配置、浏览器默认设置等

Connection:在收到响应后,应该立刻断开已建立的 TCP 连接,还是保持连接以方便下次传输。HTTP1.1 默认为 keep-alive
Cache-Control:指定缓存机制,如 no-cache
Cookie:携带之前从服务器获取的 Cookie,常用于维持用户登录状态、反爬虫
Content-Type:描述请求体中的数据格式,如 application/json
Authorization:用于传递认证信息
除了这些被广泛接受的请求头,实际开发时也可自定义请求头,前后端协调好就行
另外,HTTP规范 中字段的 key 不区分大小写,因此有些服务端会将字段 key 统一转小写,但也难保某些服务端没这么做。如果无法正常访问,可以排查下这个问题

响应状态

在响应报文的首行,响应码 + 提示语构成了响应状态。常见的有

  • 200+:成功,最常见的是 200 OK
  • 300+:重定向,服务端的 url 改变了,新的 url 会通过响应头的 Location 字段传给客户端。如果客户端是浏览器,会自动请求新的 url。一个特例是 304,代表资源未修改,浏览器可直接从缓存获取资源
  • 400+:客户端错误,请求构造有问题。例如 404,代表请求了不存在的页面;403,常代表权限不足
  • 500+:服务端错误,例如 502 表示网关错误,503 表示服务不可用

响应状态作为 HTTP 原生的错误处理机制,也有服务端彻底不用,所有响应的状态码都是 200,在 body 中传递错误信息。另外,响应码和提示语也是可以自定义的。这些都体现实际开发中的自由度

响应头字段

与请求头通用的字段不再赘述
Set-Cookie:向客户端发送的 Cookie
Location:重定向时新的 url
Server:服务端信息
Access-Control-Allow-Origin:指定允许访问资源的源,跟处理跨域请求相关
X-Frame-Options:是否允许被嵌入 <iframe>
Content-Security-Policy:用于防止跨站脚本(Cross Site Script, XSS)攻击,是X-XSS-Protection的上位替代
Referrer-Policy:控制请求头 Referer 的内容,避免泄露隐私数据。注意请求头 Referer 是错误拼写,而Referrer-Policy纠正了这个错误
Strict-Transport-Security:强制客户端使用 HTTPS 加密通信

结语

以上,我们已经认识了 HTTP 的请求与相应,大多都很容易理解。在 Header 中有相对复杂的部分,如缓存、认证、Cookie、跨域请求,需要进一步学习
玩得开心!