前端基础篇之 HTTP 协议
Category(分类): NET Protocol Status: 优
HTTP 是前端开发的重要基础知识。本文参考《图解 HTTP》等资料,尽量用简洁的语言整理 HTTP 的基础概念、版本差异、报文结构、缓存、代理、HTTPS 和常见 Web 安全问题。
目录
HTTP 协议简介
HTTP(HyperText Transfer Protocol,超文本传输协议)是 Web 中常用的应用层协议,用于规定客户端如何向服务器请求资源,以及服务器如何返回响应。
HTTP 采用请求/响应模型:
- 客户端发送请求报文,请求行中包含方法、请求目标和协议版本,请求头部携带元数据,请求体可选;
- 服务器返回响应报文,状态行中包含协议版本和状态码,响应头部携带元数据,响应内容可选。
HTTP 本身是无状态协议,协议不会自动保存不同请求之间的会话状态。但应用可以通过 Cookie、Session、Token 等机制建立会话,因此“无状态”不等于服务器永远不知道客户端身份。
浏览器会根据服务器返回的 Set-Cookie 保存符合条件的 Cookie,之后仅在域名、路径、Secure、SameSite 等规则允许时自动发送匹配的 Cookie。Cookie 并不是每个请求都会携带。
TCP/IP 协议族
TCP/IP 不是只有 TCP 和 IP 两个协议,而是一组网络协议的集合。HTTP 是其中的应用层协议之一。
TCP/IP 常用四层模型如下:
- 应用层:为应用程序提供网络服务和数据格式;
- 传输层:负责主机之间进程到进程的数据传输;
- 网际层:负责 IP 寻址、路由和数据包转发;
- 网络接口层:负责相邻节点之间的帧和物理链路传输。

应用层
应用层规定了应用程序之间如何交换数据。TCP/IP 协议族中包含许多应用协议,例如:
- FTP(File Transfer Protocol,文件传输协议);
- DNS(Domain Name System,域名系统);
- HTTP(HyperText Transfer Protocol,超文本传输协议);
- SMTP、POP3、IMAP 等邮件协议;
- SSH、NTP、DHCP 等协议。
DNS 用于把域名解析为 IP 地址,也可以查询邮件服务器等记录。例如,www.example.com 可能解析为某个 IPv4 或 IPv6 地址,但实际解析结果可能因 DNS 记录、地域和网络环境不同而变化。
传输层
传输层连接应用层和网际层,负责把数据交付给目标主机上的具体进程,端口号是传输层的重要概念。
常见传输协议包括:
- TCP(Transmission Control Protocol,传输控制协议);
- UDP(User Datagram Protocol,用户数据报协议);
- SCTP 等其他传输协议;
- QUIC 运行在 UDP 之上,为 HTTP/3 提供可靠、多路复用的传输能力。
TCP 是全双工协议,两个方向可以独立、同时传输。TCP 的可靠性来自序列号、确认、重传、流量控制和拥塞控制等机制,而不是仅仅因为有三次握手和四次挥手。
UDP 是无连接、面向数据报的协议,不保证数据可靠、有序或不重复到达,但头部开销较小,适合由应用自行设计可靠性或对实时性要求较高的场景。
网际层
网际层规定数据包如何通过路由器和其他网络设备到达目标网络,核心协议是 IP。
当目标主机不在本地网络时,主机会将 IP 数据包交给默认网关,由路由器根据路由表选择下一跳。网际层不保证数据一定到达、按序到达或只到达一次,可靠性通常由 TCP 或应用层协议提供。
网络接口层
网络接口层大致对应 OSI 模型的数据链路层和物理层,负责连接网络的链路和硬件相关部分,例如:
- 以太网、Wi-Fi 等链路技术;
- MAC 地址和帧格式;
- 网卡及其驱动;
- 网线、光纤、无线信号和连接器等物理介质。
它不只是“物理层”,也不等于所有硬件功能。
封装与解封装
发送端在层与层之间传输数据时,数据通常从应用层向下传递,每经过一层就会增加该层需要的控制信息。接收端从网络接口层向上处理,每一层读取并移除或解析属于自己的信息。
典型封装过程如下:
应用层数据
↓ 添加 TCP/UDP 首部
TCP 段 / UDP 数据报
↓ 添加 IP 首部
IP 数据报
↓ 添加链路层首部和尾部
链路层帧
封装后的数据单元通常称为:
- 应用层:数据;
- 传输层:TCP 段或 UDP 数据报;
- 网际层:IP 数据报;
- 网络接口层:帧。
解封装有点像俄罗斯套娃,但路由器通常只处理链路层帧和 IP 首部,再为下一条链路重新封装帧,不会把端到端的 TCP 和应用层数据完全拆开后再转发。
串行连接、持久连接、管道化持久连接和 HTTP/2 多路复用
串行连接
早期 HTTP/1.0 默认使用非持久连接:一次请求和响应完成后,TCP 连接通常关闭,下一个请求需要重新建立连接。HTTP/1.0 也存在 Keep-Alive 等扩展,因此不能绝对地说 HTTP/1.0 每次都断开连接。
在页面需要加载几十个资源时,频繁建立 TCP 连接会增加握手、慢启动和连接管理开销。浏览器通常会通过多个并行连接缓解 HTTP/1.0 的限制。
“短连接”和“短轮询”不是同一个概念:短连接描述连接生命周期,短轮询描述应用层定期发起请求获取数据的方式。
持久连接
HTTP/1.1 默认使用持久连接。在一条 TCP 连接上,可以依次传输多个 HTTP 请求和响应,从而减少重复建立和关闭 TCP 连接的开销。
持久连接不等于长轮询。长轮询是应用层通信方式,服务器可以暂时不返回响应,直到有数据或超时;持久连接只是允许复用已经建立的连接。
在 HTTP/1.1 普通请求处理中,同一条连接上的下一个请求通常要受到前一个请求处理方式的影响。浏览器也可以建立多个 TCP 连接并行请求。
管道化持久连接
HTTP/1.1 管道化允许客户端不等待前一个响应就发送下一个请求,但服务器必须按照请求顺序返回响应。因此,前一个慢请求仍可能阻塞后续响应,这就是 HTTP/1.1 管道化的队头阻塞问题。
现代浏览器普遍没有默认启用 HTTP/1.1 管道化,实际开发中主要由 HTTP/2 多路复用替代。
HTTP/2 多路复用
HTTP/2 引入了帧(Frame)和流(Stream):
- 帧是 HTTP/2 的基本传输单元;
- 每个帧包含 Stream Identifier,用于标识所属的流;
- 一个流通常对应一个请求/响应交互;
- 多条流的帧可以在同一个 TCP 连接中交错传输。
这样,多个请求可以并发进行,不需要等待其他请求的 HTTP 响应。HTTP/2 解决了 HTTP/1.1 管道化层面的队头阻塞,但由于底层通常仍是单条 TCP 连接,如果 TCP 层发生丢包,仍可能阻塞该连接中的所有流。
HTTP/2 通常会复用同一个连接,但浏览器不一定对同一域名永远只建立一条连接,实际行为还受到连接状态、证书、代理和实现策略影响。
WebSocket
WebSocket 是一种全双工通信协议,通常先通过 HTTP Upgrade 握手建立连接,之后双方可以独立发送消息。它不只是“HTTP 长连接”,而是握手成功后切换为 WebSocket 帧协议。
生产环境通常使用 wss://,服务端应校验握手中的 Origin 并进行身份认证。

URI
HTTP 使用 URI(Uniform Resource Identifier,统一资源标识符)标识资源。常见相关概念包括:
- URI:统一资源标识符,是标识资源的通用语法;
- URL(Uniform Resource Locator,统一资源定位符):通过位置或访问方式定位资源;
- URN(Uniform Resource Name,统一资源名称):通过名称标识资源。
URL 和 URN 都可以看作 URI 的具体形式。URI 不只表示文件,也可以标识服务、文档、实体或其他资源。
例如:
https://example.com/a.html
urn:example:resource:123
前者包含访问资源所需的位置和协议,后者使用名称标识资源。具体 URN 还需要符合对应命名空间的规则。

HTTP 版本
HTTP/1.0
早期 HTTP/1.0 默认使用非持久连接,一次请求和响应完成后通常关闭 TCP 连接。HTTP/1.0 也存在持久连接扩展,但不同客户端和服务器的支持情况并不完全一致。
HTTP/1.1
HTTP/1.1 带来了多项重要能力:
- 默认使用持久连接;
- 使用
Host请求头支持同一 IP 上的虚拟主机; - 支持条件请求和更完善的缓存控制;
- 支持
Range范围请求和206 Partial Content; - 支持分块传输编码和管道化等机制。
HTTP/1.1 中,Host 是请求消息必须包含的首部字段,响应消息不要求包含 Host。
HTTP/2
HTTP/2 的主要改进包括:
二进制分帧
HTTP/1.x 的消息语法主要基于文本,但消息体可以是二进制。HTTP/2 使用二进制帧格式传输控制信息和数据,便于解析和扩展。
多路复用
一个 TCP 连接中可以存在多条流,不同流的帧可以交错传输。浏览器通过帧中的流标识把数据交给对应的请求。
HTTP/2 解决了 HTTP 层面的队头阻塞,但 TCP 层面的队头阻塞仍然存在。
头部压缩
HTTP/2 使用 HPACK 压缩头部,通过静态表、动态表和 Huffman 编码减少重复首部字段的传输量。HTTP/3 使用的是 QPACK,设计上适配 QUIC 的传输特性。
服务端推送
HTTP/2 曾支持服务端推送,即服务器在客户端明确请求之前推送资源。但由于缓存判断、资源选择和实现复杂度等问题,现代浏览器已经逐步弃用或移除该能力,不应把它作为新项目的主要优化手段。
HTTP/3
HTTP/2 通常使用单条 TCP 连接进行多路复用。当 TCP 连接中出现丢包时,TCP 必须保证字节流按序交付,这可能使多个 HTTP/2 流共同受到影响。
HTTP/3 使用 IETF 标准化的 QUIC 协议。QUIC 运行在 UDP 之上,但在 UDP 之上实现了:
- 可靠传输和重传;
- 每条流独立的有序交付;
- 流量控制和拥塞控制;
- TLS 1.3 加密握手;
- 连接迁移;
- 连接建立和会话恢复优化。
避免跨流队头阻塞
QUIC 的不同流具有相对独立的传输状态。某一条流的数据包丢失时,其他流在拥有可用数据的情况下可以继续处理,从而避免 TCP 单字节流带来的跨流队头阻塞。不过,所有流仍然共享连接的网络带宽和拥塞控制,严重的网络拥塞仍会影响整个连接。
连接迁移
QUIC 使用 Connection ID 标识连接,不是简单依赖客户端 IP、端口和服务器 IP、端口。因此,移动设备切换 Wi-Fi 和蜂窝网络后,连接有机会继续使用,而不必像 TCP 那样仅因为源 IP 改变就必然重新建立连接。
连接迁移仍然需要路径验证和安全检查,不能简单理解为“只要 ID 不变就完全不需要握手”。0-RTT 可以减少部分握手延迟,但早期数据存在重放风险,不适合直接执行非幂等操作。
HTTP 报文
用于 HTTP 协议交互的信息称为 HTTP 报文。客户端发送请求报文,服务端返回响应报文。
请求报文
请求报文通常由以下部分组成:
- 请求行:方法、请求目标、协议版本;
- 请求首部;
- 空行;
- 可选的消息内容。
示例:
GET /index.html HTTP/1.1
Host: example.com
Accept: text/html
请求目标位于请求行,不属于请求首部。请求内容是否存在取决于方法和具体请求。


响应报文
响应报文通常由以下部分组成:
- 状态行:协议版本、状态码和原因短语;
- 响应首部;
- 空行;
- 可选的消息内容。
示例:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 18
<h1>Hello</h1>
Server 等服务器信息字段是可选的,并非响应报文的固定组成部分。


请求方法
GET:请求获取资源,通常应当是安全且幂等的;POST:提交数据,请求服务器进行处理,常用于创建资源或触发操作;PUT:使用请求内容创建或完整替换目标 URI 对应的资源,通常设计为幂等;PATCH:对资源进行部分修改;DELETE:请求删除指定资源,是否立即物理删除由服务器决定;HEAD:获取与 GET 类似的响应首部,但不返回响应内容;OPTIONS:询问目标资源或服务器支持的通信选项;CONNECT:建立到目标服务器的隧道,常用于代理;TRACE:回显请求链路信息,生产环境通常会禁用以降低风险。
方法的幂等性和安全性是协议语义,不等于服务器一定正确实现。POST 也可能用于查询,但不应因此改变其一般语义。
状态码
HTTP 状态码表示服务器对请求的处理结果。
2XX 成功
| 状态码 | 含义 |
|---|---|
200 OK | 请求成功,响应内容取决于具体方法和资源 |
201 Created | 请求成功创建了资源 |
202 Accepted | 请求已接受,但处理尚未完成 |
204 No Content | 请求成功,响应不包含消息内容 |
206 Partial Content | 范围请求成功,返回部分内容 |
3XX 重定向或缓存相关
| 状态码 | 含义 |
|---|---|
301 Moved Permanently | 资源具有新的永久 URI |
302 Found | 资源暂时位于另一个 URI,历史客户端可能将 POST 改为 GET |
303 See Other | 应使用 GET 或 HEAD 请求另一个 URI 获取结果 |
304 Not Modified | 条件请求命中缓存,响应不包含内容,与重定向无关 |
307 Temporary Redirect | 临时重定向,客户端应保持原方法和请求内容 |
308 Permanent Redirect | 永久重定向,客户端应保持原方法和请求内容 |
4XX 客户端错误
| 状态码 | 含义 |
|---|---|
400 Bad Request | 请求语法或格式错误 |
401 Unauthorized | 缺少有效认证信息,通常配合 WWW-Authenticate |
403 Forbidden | 服务器理解请求,但拒绝处理 |
404 Not Found | 未找到目标资源,或服务器不愿透露其存在 |
405 Method Not Allowed | 目标资源不支持当前请求方法 |
409 Conflict | 请求与资源当前状态冲突 |
429 Too Many Requests | 请求频率超过限制 |
5XX 服务器错误
| 状态码 | 含义 |
|---|---|
500 Internal Server Error | 服务器内部发生未知错误 |
501 Not Implemented | 服务器不支持完成请求所需的功能 |
502 Bad Gateway | 网关或代理从上游收到无效响应 |
503 Service Unavailable | 服务器暂时无法处理请求,可能处于过载或维护状态 |
504 Gateway Timeout | 网关或代理等待上游响应超时 |
首部字段
HTTP 首部字段名称不区分大小写。HTTP/2 和 HTTP/3 在传输层面要求首部名称使用小写。下面按常见用途整理部分首部字段。
通用或连接相关首部
| 首部 | 作用 |
|---|---|
Cache-Control | 控制缓存,如 no-cache 表示使用前重新验证,no-store 表示不存储,max-age 表示最大新鲜时间,public/private 控制共享缓存使用方式 |
Connection | HTTP/1.1 的逐跳连接控制,如 close;HTTP/2 和 HTTP/3 不应使用该首部 |
Date | 报文生成时间 |
Pragma | 主要用于 HTTP/1.0 兼容,例如旧式缓存控制 |
Via | 记录经过的代理或网关 |
Transfer-Encoding | HTTP/1.1 的传输编码,例如 chunked,HTTP/2 和 HTTP/3 不使用 HTTP/1.1 分块编码 |
Upgrade | 请求协议升级,例如 WebSocket,通常配合 Connection: Upgrade |
Warning | 历史缓存警告字段,已不建议在现代 HTTP 中使用 |
请求首部
| 首部 | 作用 |
|---|---|
Accept | 客户端可接受的媒体类型,如 application/json、text/html |
Accept-Charset | 可接受的字符集,已基本废弃,浏览器通常不发送 |
Accept-Encoding | 可接受的内容编码,如 gzip、br、deflate |
Accept-Language | 可接受的语言,如 zh-CN,zh;q=0.9,en;q=0.8 |
Authorization | 客户端认证信息,如 Basic 或 Bearer 凭据 |
Cookie | 客户端发送给服务器的 Cookie |
Expect | 请求客户端希望服务器执行的行为,常见值是 100-continue |
From | 请求方邮箱地址,较少使用 |
Host | 请求目标主机和端口,HTTP/1.1 请求中必须包含;HTTP/2/3 使用 :authority 表示类似信息 |
If-Match | 根据 ETag 进行条件请求,失败时通常返回 412 |
If-Modified-Since | 根据 Last-Modified 时间进行缓存验证 |
If-None-Match | 根据 ETag 进行缓存验证或条件操作 |
User-Agent | 客户端软件信息,可被伪造 |
Max-Forwards | 限制 TRACE、OPTIONS 等请求经过代理的次数 |
Proxy-Authorization | 向代理服务器发送认证信息 |
Range | 请求资源的某一部分,例如 bytes=0-1023 |
Referer | 请求来源页面,可能因隐私策略被省略或截断 |
TE | 声明客户端可接受的传输编码或 trailers,不能与 Accept-Encoding 混淆 |
响应首部
| 首部 | 作用 |
|---|---|
Accept-Ranges | 告知是否支持范围请求,常见值为 bytes |
Age | 响应在共享缓存中存在的秒数 |
ETag | 资源表示的验证标识,可用于条件请求 |
Location | 重定向目标,或 201 Created 中新建资源的位置 |
Proxy-Authenticate | 代理要求客户端认证时发送的认证挑战 |
Server | 服务器软件信息,可选,不建议暴露过多版本细节 |
WWW-Authenticate | 401 响应中的认证挑战 |
Set-Cookie | 指示浏览器保存或更新 Cookie |
表示和内容相关首部
| 首部 | 作用 |
|---|---|
Allow | 目标资源支持的请求方法列表 |
Content-Encoding | 内容编码,如 gzip、br |
Content-Language | 内容使用的语言,如 zh-CN |
Content-Length | 消息内容的字节长度,可用于请求或响应 |
Content-Location | 当前表示的备用位置 |
Content-MD5 | 历史字段,MD5 是摘要而不是加密,现代应用不建议使用 |
Content-Range | 部分响应对应的资源范围 |
Content-Type | 内容媒体类型,如 application/json; charset=utf-8 |
Expires | 内容过期时间,缓存应结合 Cache-Control 判断 |
Last-Modified | 资源表示的最后修改时间 |

两种 CORS 请求
浏览器进行跨源 HTTP 请求时,会根据方法、请求头和内容类型等条件判断是否需要预检。常用分类是简单请求和需要预检的请求。
简单请求
通常需要同时满足以下条件:
- 请求方法是
GET、HEAD或POST; - 手动设置的请求头满足 CORS safelisted request-header 限制;
Content-Type是以下三种之一:text/plain;multipart/form-data;application/x-www-form-urlencoded;
- XMLHttpRequest 上传对象没有注册会触发预检的事件监听器。
简单请求通常会先发送实际请求,再由浏览器根据响应头判断页面脚本能否读取响应。即使浏览器阻止脚本读取响应,请求也可能已经造成服务器副作用,因此 CORS 不能代替 CSRF 防护。
需要预检的请求
以下情况通常会触发预检:
- 使用
PUT、PATCH、DELETE等方法; - 使用
application/json等不属于简单请求的内容类型; - 设置不满足 safelist 条件的自定义请求头;
- 使用其他会改变 CORS 预检条件的请求配置。
仅仅携带凭据本身不会自动触发预检,但服务端仍必须正确返回 Access-Control-Allow-Credentials: true,并使用明确的 Access-Control-Allow-Origin。
浏览器会先发送 OPTIONS 请求,并携带:
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
服务器需要返回允许的源、方法和请求头:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 600
如果预检失败,浏览器通常不会发送真正的请求。反向代理让浏览器请求同源地址时,不会因为后端代理目标不同而自动触发浏览器 CORS 预检。
Web 服务器
这里不重点讨论服务器是 Apache 还是 Nginx,而是介绍服务器在 HTTP 通信中的常见角色。一台服务器可以作为源服务器、代理服务器或反向代理,也可以通过虚拟主机承载多个网站。
虚拟主机
HTTP/1.1 允许一台服务器根据请求中的 Host 为多个域名提供服务。例如:
- DNS 将
www.example.com解析到某个 IP 地址; - 客户端连接该 IP;
- HTTP/1.1 请求通过
Host告知目标域名; - 服务器根据
Host选择对应的虚拟主机配置。
HTTPS 场景下,TLS 握手通常还会通过 SNI 提供目标域名,以便服务器选择证书;HTTP/2 和 HTTP/3 使用 :authority 表示类似的请求目标主机信息。
同一个 IP 上可以部署多个域名,但不要求一定只有一台物理服务器,实际也可能通过负载均衡将请求分发到多个后端实例。
代理服务器
代理服务器位于客户端和源服务器之间,负责转发、缓存、鉴权、访问控制或负载均衡。
正向代理
正向代理代表客户端访问源服务器:
- 客户端向代理发送请求,并指定目标服务器;
- 代理向目标服务器发起请求;
- 代理获取目标响应;
- 代理将响应返回客户端。
客户端通常知道自己使用了正向代理。代理可能隐藏客户端地址,但如果通过请求头传递 X-Forwarded-For 等信息,目标服务器仍可能知道原始客户端信息。
反向代理
反向代理代表服务器接收客户端请求:
- 客户端请求统一入口;
- 反向代理根据域名、路径、负载策略选择上游服务;
- 代理将请求转发给后端;
- 代理把响应返回客户端。
客户端通常只需要知道反向代理地址,不需要知道具体后端实例。Nginx、Caddy、Apache HTTP Server 和云负载均衡器都可以承担反向代理角色。
通过开发服务器代理解决跨域
本地前端开发服务器可能运行在:
http://localhost:8080
目标接口运行在:
http://api.example.com
如果浏览器直接请求目标接口,就会受到同源策略限制。开发服务器代理的做法是:
浏览器 -> localhost:8080/api -> 开发服务器 -> api.example.com
浏览器只请求同源的 /api,开发服务器再从服务端请求目标接口。服务器到服务器的请求不受浏览器同源策略限制。
Vue CLI 示例配置:
// vue.config.js
module.exports = {
devServer: {
port: 8080,
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
secure: true,
// 如果目标接口不需要 /api 前缀,可以取消注释
// pathRewrite: { '^/api': '' }
}
}
}
}
前端请求应使用与代理规则匹配的相对路径:
axios.create({
baseURL: '/api'
})
baseURL 不一定必须是 '/',关键是请求 URL 需要保持同源,并且能够匹配代理配置。开发代理不等同于生产环境的安全防护,生产环境通常使用 Nginx、网关或后端服务进行统一代理。
缓存服务器
缓存服务器或 CDN 会在浏览器和源服务器之间保存可复用的响应,以减少源站压力和网络延迟。缓存是否可以保存和复用响应,需要根据 Cache-Control、Expires、ETag、Last-Modified、Vary 等字段判断。
缓存服务器不一定只有一层,也不一定总是先访问缓存再访问源站。对于带用户身份的响应,应谨慎配置缓存,避免把一个用户的数据返回给另一个用户。
HTTPS
HTTP 本身不提供加密、完整性保护和服务器身份认证。直接使用 http:// 时,网络中的攻击者可能读取或篡改传输内容。
对称加密
对称加密使用同一个秘密密钥加密和解密,速度通常较快,适合大量应用数据传输。但通信双方需要安全地得到同一个密钥,这就是密钥分发问题。
非对称密码学
非对称密码学使用公钥和私钥:
- 公钥加密、私钥解密可以用于机密性;
- 私钥签名、公钥验证用于身份认证和完整性。
“私钥加密、公钥解密”常被用来类比数字签名,但不能把它当成普通机密性加密流程。攻击者可以看到公钥,真正需要保护的是私钥以及证书信任链。
证书和数字签名
服务器证书通常是 X.509 证书,包含:
- 服务器公钥;
- 域名信息,现代证书主要通过 SAN 表示;
- 有效期;
- 签发者和用途;
- CA 对证书内容的数字签名。
CA 不是用自己的私钥“加密服务器公钥”,而是对证书内容计算摘要并生成数字签名。浏览器会检查证书链、域名匹配、有效期、用途和本地信任库。
免费证书和付费证书都存在,是否收费取决于 CA、验证类型和服务商。证书签名不能保证服务器本身没有被入侵,也不能保护已经被恶意软件控制的客户端。
TLS 的现代握手
HTTPS 更准确的表达是:
HTTPS = HTTP over TLS
SSL 已经废弃,现代 HTTPS 主要使用 TLS 1.2 或 TLS 1.3。
TLS 1.3 通常使用临时 ECDHE 进行密钥协商:
- 客户端发送
ClientHello和密钥交换参数; - 服务端返回
ServerHello、证书和握手签名; - 客户端验证证书链、域名和签名;
- 双方通过 ECDHE 计算共享秘密;
- 双方使用 HKDF 派生会话密钥;
- 应用数据使用 AES-GCM 或 ChaCha20-Poly1305 等 AEAD 算法保护。
早期 TLS 1.2 可以使用 RSA 密钥交换,但现代 TLS 1.3 不使用静态 RSA 密钥交换。ECDHE 还可以提供前向保密:即使服务器长期私钥日后泄露,也不能直接解密过去捕获的 TLS 1.3 会话数据。

HTTPS 的特点和限制
- 机密性:防止传输中的第三方直接读取 HTTP 内容;
- 完整性:通过 AEAD 等机制检测传输内容是否被篡改;
- 身份认证:通过证书和信任链验证服务器身份;
- 端口:HTTPS 通常使用 443,但端口不是安全性的来源;
- 底层协议:HTTP/1.1 和 HTTP/2 通常运行在 TCP + TLS 上,HTTP/3 运行在 QUIC + TLS 上。
HTTPS 主要保护传输过程,不能替代应用层认证、权限控制、输入校验和端点安全。IP 地址、连接时间、流量大小等部分元数据也可能被观察到。
Web 安全防范
XSS 攻击
XSS(Cross-Site Scripting,跨站脚本攻击)是攻击者让不可信输入以脚本或恶意 HTML 的形式在受信任页面中执行。常见类型包括:
- 反射型 XSS:恶意内容来自当前请求,服务器立即反射到响应;
- 存储型 XSS:恶意内容被保存到数据库或其他存储中,之后被展示给用户;
- DOM 型 XSS:前端 JavaScript 不安全地处理 URL、输入框等数据。
XSS 不只是“在 URL 中插入 <script>”,也可能通过 HTML 属性、事件处理器、JavaScript 字符串、CSS 或 URL 上下文发生。不能依赖浏览器自动拦截所有 XSS。
防护重点包括:
- 在正确的上下文进行输出编码;
- 使用模板引擎的自动转义;
- 不要把不可信内容直接交给
innerHTML; - 对确实需要展示的 HTML 使用经过配置的白名单清洗器;
- 配置 Content Security Policy(CSP);
- Cookie 使用
HttpOnly、Secure等属性降低被脚本读取的风险。
示例中的 xss 库只能用于特定 HTML 清洗场景,不能替代 JavaScript、CSS、URL 等不同上下文的安全编码:
const xss = require('xss')
const html = xss(
'<h1 id="title">XSS Demo</h1><script>alert("xss")</script>'
)
console.log(html)
CSRF 攻击
CSRF(Cross-Site Request Forgery,跨站请求伪造)利用浏览器自动携带 Cookie 或其他凭据的行为,让用户在不知情的情况下向目标网站发送有副作用的请求。
例如,一个不安全的关注接口使用 GET 修改状态:
https://example.com/follow?id=123
恶意页面可能嵌入:
<img src="https://example.com/follow?id=123" alt="">
如果浏览器携带了目标网站的有效 Cookie,就可能执行关注操作。即使改成 POST,也可能通过跨源表单提交,因此不能只依赖同源策略。
CSRF 的本质是:身份凭据可能自动被浏览器携带,但服务器无法确认请求是否得到用户主动批准。
常见防护方式:
- GET、HEAD 等安全方法不应修改服务器状态;
- 使用不可预测且与会话绑定的 CSRF Token;
- Cookie 配置合理的
SameSite、Secure和HttpOnly; - 校验请求的
Origin,必要时校验Referer; - 对敏感操作进行重新认证或二次确认;
- 不要把“禁止 CORS”当作 CSRF 防护,CORS 主要控制脚本读取响应。
HttpOnly 只能减少脚本读取 Cookie 的风险,不能阻止浏览器在符合条件时自动发送 Cookie。
点击劫持
点击劫持是一种视觉欺骗攻击。攻击者把目标网站嵌入自己的页面,通过透明或伪装的 iframe 诱导用户点击目标页面中的按钮。

防护可以使用:
X-Frame-Options: DENY
或:
X-Frame-Options: SAMEORIGIN
ALLOW-FROM 已被现代浏览器废弃或支持不一致,不建议作为主要方案。更现代的方案是配置 CSP:
Content-Security-Policy: frame-ancestors 'none'
如果业务确实允许部分站点嵌入,可以在 frame-ancestors 中明确列出允许的源。
中间人攻击
中间人攻击是攻击者同时与客户端和服务端建立连接,并让双方误以为彼此正在直接通信。攻击者可以读取、转发甚至修改通信内容。

单纯的对称加密、非对称加密或密钥交换不能自动解决身份认证问题。如果公钥被中间人替换,客户端可能把数据加密给攻击者。
HTTPS 通过证书、CA 信任链、握手签名和会话密钥协商来验证服务端身份,并保护传输中的数据。但如果用户安装了恶意根证书、关闭证书校验、客户端或服务器已经被入侵,HTTPS 也不能保证绝对安全。
小结
本文整理了前端需要掌握的 HTTP 相关知识:
- HTTP 是无状态的应用层请求/响应协议;
- HTTP/1.1 通过持久连接降低连接开销;
- HTTP/2 通过二进制分帧和多路复用提升并发传输效率;
- HTTP/3 使用 QUIC,减少 TCP 层面的跨流队头阻塞;
- URI、请求方法、状态码和首部共同描述 HTTP 交互;
- CORS、缓存、代理和虚拟主机是实际 Web 开发的重要内容;
- HTTPS 通过 TLS 提供传输加密、完整性保护和服务器身份认证;
- XSS、CSRF、点击劫持和中间人攻击需要分别采取针对性防护。
推荐阅读: