HTTP 教程
HTTP(HyperText Transfer Protocol,超文本传输协议)是 Web 世界的基石协议。浏览器与服务器之间的一切通信,都建立在 HTTP 之上。
什么是 HTTP
HTTP 是一种请求-响应模式的文本协议:客户端(通常是浏览器)发出请求,服务器返回响应。整个过程简单直接,是理解 Web 工作原理的关键。
一次 HTTP 通信的流程
- 浏览器输入网址,解析出域名和端口
- DNS 解析域名得到服务器 IP
- 浏览器与服务器建立 TCP 连接
- 浏览器发送 HTTP 请求(请求行 + 请求头 + 请求体)
- 服务器处理请求,返回 HTTP 响应(状态行 + 响应头 + 响应体)
- 浏览器渲染页面,连接可复用或关闭
HTTP 的特点
| 特点 | 说明 |
|---|---|
| 简单 | 文本协议,头信息可读性强 |
| 无状态 | 每个请求独立,服务器不记忆之前请求(用 Cookie/Session 补充) |
| 可扩展 | 通过自定义头信息扩展能力 |
| 基于 TCP | 默认 80 端口,可靠传输 |
HTTP 版本演进
| 版本 | 年份 | 主要改进 |
|---|---|---|
| HTTP/1.0 | 1996 | 首个被广泛使用的版本 |
| HTTP/1.1 | 1997 | 持久连接、虚拟主机(Host 头)、管线化 |
| HTTP/2 | 2015 | 多路复用、头部压缩、服务器推送 |
| HTTP/3 | 2022 | 基于 QUIC/UDP,降低延迟 |
查看 HTTP 通信
浏览器按 F12 打开开发者工具 → Network(网络)面板,即可看到每个请求的方法、状态码、耗时、请求头与响应头——这是调试 Web 应用最重要的工具。
地址栏输入 http:// 开头即用 HTTP 明文传输;https:// 则是在 HTTP 外加了一层 TLS 加密(见后续章节)。
HTTP/HTTPS 简介
本节讲清 HTTP 与 HTTPS 的区别,以及为什么现代网站必须使用 HTTPS。
HTTP 的先天不足
HTTP 使用明文传输,数据在网络上裸奔,存在三大风险:
- 窃听:数据包可被中间人截获读取(密码、银行卡号泄露)
- 篡改:内容可被中间人修改(注入广告、恶意脚本)
- 冒充:无法确认服务器真实身份(钓鱼风险)
HTTPS = HTTP + TLS
HTTPS(HyperText Transfer Protocol Secure)在 HTTP 和 TCP 之间加入一层 TLS(传输层安全协议)加密:
HTTP : 应用层(HTTP) → TCP → IP
HTTPS : 应用层(HTTP) → TLS(加密) → TCP → IP
HTTPS 提供三重保障
| 保障 | 机制 | 解决 |
|---|---|---|
| 加密传输 | 对称 + 非对称混合加密 | 防窃听 |
| 完整性 | 消息认证码 / 哈希校验 | 防篡改 |
| 身份认证 | 数字证书(CA 签发) | 防冒充 |
TLS 握手过程(简化)
- 客户端发起连接,声明支持的加密算法
- 服务器返回数字证书(含公钥)
- 客户端验证证书合法性(是否受信任 CA 签发、域名是否匹配、是否过期)
- 双方协商出对称密钥(用公钥加密传输)
- 之后所有数据用对称密钥加密通信(高效)
如何获得 HTTPS
- 免费证书:Let's Encrypt(自动续期,宝塔面板一键申请)
- 云厂商证书:阿里云、腾讯云免费/付费证书
- 自签名证书:仅用于内网测试,浏览器会报警
2023 年起,Chrome/Firefox 已把纯 HTTP 页面标记为"不安全"。涉及登录、支付、个人信息的网站必须启用 HTTPS。
HTTP 消息结构
HTTP 消息分为两类:客户端发送的请求消息和服务器返回的响应消息。两者结构类似,都由"起始行 + 头字段 + 空行 + 消息体"组成。
请求消息结构
GET /index.html HTTP/1.1 ← 请求行:方法 + 路径 + 版本
Host: www.example.com ← 请求头(多个)
User-Agent: Mozilla/5.0
Accept: text/html
← 空行(必须)
(请求体,GET 通常为空) ← 消息体
响应消息结构
HTTP/1.1 200 OK ← 状态行:版本 + 状态码 + 原因短语
Content-Type: text/html ← 响应头(多个)
Content-Length: 1024
Set-Cookie: session=abc123
← 空行
<html>...</html> ← 响应体(HTML 等)
起始行详解
| 消息 | 起始行 | 示例 |
|---|---|---|
| 请求 | 请求行 | POST /api/login HTTP/1.1 |
| 响应 | 状态行 | HTTP/1.1 201 Created |
常用请求头
| 请求头 | 作用 |
|---|---|
Host | 目标主机(HTTP/1.1 必填) |
User-Agent | 客户端标识(浏览器/爬虫) |
Accept | 可接受的响应类型 |
Accept-Language | 偏好语言(zh-CN 等) |
Content-Type | 请求体类型(如 JSON) |
Content-Length | 请求体字节数 |
Authorization | 认证凭据(Bearer Token 等) |
Cookie | 携带的会话 Cookie |
Referer | 来源页面地址 |
常用响应头
| 响应头 | 作用 |
|---|---|
Content-Type | 响应体类型(text/html、application/json) |
Content-Length | 响应体字节数 |
Set-Cookie | 让浏览器种下 Cookie |
Location | 重定向地址(配合 3xx 状态码) |
Cache-Control | 缓存策略 |
Access-Control-Allow-Origin | CORS 跨域许可 |
空行是头与体的分隔符,不可缺少;头字段名不区分大小写,但习惯用首字母大写。
HTTP 请求方法
HTTP 定义了多种请求方法,每种方法表达一种操作语义。了解它们,是设计 API 和理解 Web 的基础。
最常用的四种方法
| 方法 | 含义 | 常见场景 |
|---|---|---|
GET | 获取资源 | 打开网页、查询列表 |
POST | 创建/提交资源 | 提交表单、登录注册 |
PUT | 整体更新资源 | 修改用户完整信息 |
DELETE | 删除资源 | 删除文章、注销账号 |
其他方法
| 方法 | 含义 | 说明 |
|---|---|---|
HEAD | 只获取响应头 | 探测资源是否存在、检查时效 |
PATCH | 部分更新资源 | 只修改某个字段 |
OPTIONS | 查询支持的方法 | CORS 预检请求 |
CONNECT | 建立隧道 | HTTPS 代理 |
TRACE | 回显请求 | 诊断用,常被禁用 |
GET 与 POST 的关键区别
- GET:参数在 URL 中,可被收藏/分享/缓存,浏览器回退安全;不应产生副作用(只读)
- POST:参数在请求体中,更安全、容量更大;会产生副作用(写操作)
// GET:参数在 URL
GET /search?q=python&page=1 HTTP/1.1
// POST:参数在请求体
POST /api/login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin&password=123456
幂等性概念
幂等:同一个请求执行多次,结果与执行一次相同。GET、PUT、DELETE 都是幂等的(删除不存在的资源也返回成功);POST 不幂等(重复提交会创建多条数据)——这也是为什么表单重复提交会产生重复订单。
在开发中实践
// 浏览器侧
fetch("/api/users/1", { method: "DELETE" }); // 删除
fetch("/api/users/1", { method: "PUT", body: JSON.stringify(user) }); // 整体更新
fetch("/api/users/1", { method: "PATCH", body: JSON.stringify({ age: 26 }) }); // 部分更新
GET 请求不应携带敏感数据(会出现在 URL、浏览器历史、服务器日志中);写操作务必使用 POST/PUT/DELETE。
HTTP 响应头信息
服务器返回的响应头携带了大量关于响应的元信息,理解它们有助于调试和优化 Web 应用。
常见的响应头字段
| 响应头 | 示例值 | 说明 |
|---|---|---|
Content-Type | application/json; charset=utf-8 | 响应体媒体类型与编码 |
Content-Length | 2048 | 响应体字节数 |
Date | Mon, 11 Aug 2026 10:00:00 GMT | 响应时间 |
Server | nginx | 服务器软件 |
Set-Cookie | session=abc; Path=/; HttpOnly | 写入 Cookie |
Location | /new-page | 重定向目标 |
Cache-Control | max-age=3600 | 缓存策略 |
Last-Modified | Wed, 01 Aug 2026 08:00:00 GMT | 资源最后修改时间 |
ETag | "33a64df5" | 资源校验标记 |
与缓存相关的响应头
Cache-Control: max-age=86400 // 缓存 1 天
Cache-Control: no-cache // 使用前必须校验
Cache-Control: no-store // 禁止缓存(敏感数据)
配合 ETag 或 Last-Modified,浏览器可以发起条件请求:带 If-None-Match 或 If-Modified-Since 头,若资源未变,服务器返回 304 Not Modified,节省带宽。
与安全相关的响应头
Strict-Transport-Security: max-age=31536000 // 强制 HTTPS
Content-Security-Policy: default-src 'self' // 内容安全策略,防 XSS
X-Frame-Options: DENY // 防点击劫持(禁止被 iframe 嵌入)
X-Content-Type-Options: nosniff // 禁止 MIME 嗅探
Referrer-Policy: no-referrer // 控制 Referer 泄露
查看响应头
- 开发者工具 → Network → 点击某个请求
- 在 Headers(响应头)面板查看全部字段
- 或命令行:
curl -I https://www.example.com只看响应头
curl -I https://www.laowang.click
# HTTP/2 200
# content-type: text/html; charset=utf-8
# server: nginx
# ...
排查"页面突然空白 / 加载慢"时,先看响应头:Content-Type 对不对、Cache-Control 是否合理、有无 304 等。
HTTP 状态码
HTTP 状态码是服务器告诉客户端请求结果的三位数字。看懂状态码,就能快速定位问题。
状态码分类
| 分类 | 范围 | 含义 |
|---|---|---|
| 1xx | 100-199 | 信息性响应(继续处理) |
| 2xx | 200-299 | 成功 |
| 3xx | 300-399 | 重定向(需进一步操作) |
| 4xx | 400-499 | 客户端错误 |
| 5xx | 500-599 | 服务器错误 |
2xx 成功
| 状态码 | 说明 |
|---|---|
200 OK | 请求成功,最常见的状态码 |
201 Created | 创建成功(POST 建资源) |
204 No Content | 成功但无内容返回 |
3xx 重定向
| 状态码 | 说明 |
|---|---|
301 Moved Permanently | 永久重定向(SEO 会更新链接) |
302 Found | 临时重定向(默认) |
304 Not Modified | 资源未变,用缓存 |
4xx 客户端错误
| 状态码 | 说明 | 常见场景 |
|---|---|---|
400 Bad Request | 请求格式错误 | JSON 语法错误 |
401 Unauthorized | 未认证 | 没登录或 Token 失效 |
403 Forbidden | 无权限 | 登录了但禁止访问 |
404 Not Found | 资源不存在 | 链接写错、文件缺失 |
405 Method Not Allowed | 方法不允许 | GET 接口被 POST 调用 |
409 Conflict | 冲突 | 用户名已存在 |
429 Too Many Requests | 请求过多 | 触发限流 |
5xx 服务器错误
| 状态码 | 说明 | 常见场景 |
|---|---|---|
500 Internal Server Error | 服务器内部错误 | 代码异常、数据库挂了 |
502 Bad Gateway | 网关错误 | 反代后上游服务未启动 |
503 Service Unavailable | 服务不可用 | 过载、维护中 |
504 Gateway Timeout | 网关超时 | 上游响应超时 |
状态码速查口诀
- 2xx 成了,3xx 挪了,4xx 你错了,5xx 它挂了
- 404 → 检查 URL/文件;403 → 检查权限;502/504 → 检查后端服务
调试时在浏览器开发者工具 Network 面板按状态码筛选(红色=4xx/5xx),能快速找出失败请求。
HTTP content-type
Content-Type(内容类型)头告诉接收方:这段数据的格式是什么。它决定了浏览器如何解析响应、服务器如何解析请求体。
Content-Type 的格式
Content-Type: 类型/子类型; 参数
示例:
Content-Type: text/html; charset=utf-8
Content-Type: application/json
Content-Type: image/png
常用 Content-Type
| 类型 | 说明 | 典型场景 |
|---|---|---|
text/html | HTML 网页 | 网页响应 |
text/plain | 纯文本 | 普通文本文件 |
text/css | 样式表 | .css 文件 |
application/json | JSON 数据 | API 响应/请求 |
application/javascript | JS 脚本 | .js 文件 |
application/xml | XML 数据 | SOAP、RSS |
application/x-www-form-urlencoded | 表单编码 | 传统表单提交 |
multipart/form-data | 多部分表单 | 文件上传 |
image/png / jpeg / gif / webp | 图片 | 图片资源 |
application/pdf | PDF 文档 | 下载 |
application/zip | 压缩包 | 下载 |
请求中的 Content-Type
POST/PUT 请求发送数据时,必须声明正确的类型:
// 发送 JSON
fetch("/api/user", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "张三" })
});
// 发送表单(自动处理)
const formData = new FormData(form);
fetch("/api/upload", { method: "POST", body: formData });
// 浏览器自动设置 multipart/form-data
响应中的 Content-Type
服务器返回 JSON 时必须设置 Content-Type: application/json,否则浏览器不知道如何解析:
# FastAPI 自动设置
from fastapi import FastAPI
app = FastAPI()
@app.get("/api/user")
def get_user():
return {"name": "张三"} # 自动响应 application/json
charset 与编码
charset=utf-8 声明字符编码。中文网站必须用 UTF-8,否则会出现乱码。如今 text/html 默认已是 UTF-8,但显式声明更稳妥。
接口返回了 JSON 但 Content-Type 是 text/html,前端 res.json() 仍可能解析成功,但某些严格客户端会报错。保持类型一致是好习惯。
MIME 类型
MIME 类型(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)是 Content-Type 的基础——它用"类型/子类型"的形式描述文件内容格式,让浏览器知道如何打开各类资源。
MIME 类型的作用
服务器在响应中带 Content-Type(即 MIME 类型),浏览器据此决定处理方式:
text/html→ 渲染为网页image/png→ 显示为图片application/pdf→ 打开 PDF 阅读器application/octet-stream→ 触发下载
常见文件扩展名与 MIME 对照
| 扩展名 | MIME 类型 |
|---|---|
.html | text/html |
.css | text/css |
.js | application/javascript |
.json | application/json |
.xml | application/xml |
.txt | text/plain |
.png | image/png |
.jpg / .jpeg | image/jpeg |
.gif | image/gif |
.webp | image/webp |
.svg | image/svg+xml |
.mp4 | video/mp4 |
.mp3 | audio/mpeg |
.pdf | application/pdf |
.zip | application/zip |
.doc | application/msword |
.xls | application/vnd.ms-excel |
.woff2 | font/woff2 |
浏览器如何识别类型
- 优先看响应头
Content-Type - 若缺失,浏览器可能嗅探文件内容(MIME Sniffing)
- 安全头
X-Content-Type-Options: nosniff可禁止嗅探(防攻击)
静态文件与 MIME
Nginx/Apache 等 Web 服务器内置了扩展名 → MIME 映射表,配置正确就能自动返回合适的类型。若服务器配置错误(如把 .js 当 text/plain 返回),脚本可能无法执行。
# nginx 示例:自定义 MIME
location ~ \.m3u8$ {
add_header Content-Type application/vnd.apple.mpegurl;
}
排查"图片不显示 / 文件打不开"时,用开发者工具看响应的 Content-Type 是否正确。
HTTP2
HTTP/2(2015 年发布)是 HTTP/1.1 之后的大版本升级,重点解决现代网页大量并发请求下的性能瓶颈,如今已被绝大多数网站使用。
HTTP/1.1 的痛点
- 队头阻塞:一个连接上只能串行处理请求,前一个慢了后面全等
- 连接数限制:浏览器对单域名并发连接有限制(6 个左右),资源多时要排队
- 头部冗余:每次请求都重复发送大段相同的头信息
HTTP/2 的核心特性
| 特性 | 说明 |
|---|---|
| 多路复用 | 一个连接上并发传输多个请求/响应,互不阻塞 |
| 头部压缩 | HPACK 算法压缩头信息,重复字段只发一次 |
| 二进制分帧 | 数据改为二进制帧传输,解析更高效 |
| 服务器推送 | 服务器可主动推送资源(如 CSS/JS,现已少用) |
| 流量优先级 | 可设置资源加载优先级 |
HTTP/1.1 vs HTTP/2
| 对比项 | HTTP/1.1 | HTTP/2 |
|---|---|---|
| 数据传输 | 文本 | 二进制分帧 |
| 连接复用 | 串行(有队头阻塞) | 多路复用(无阻塞) |
| 头部开销 | 重复发送 | HPACK 压缩 |
| 并发能力 | 靠多连接 | 单连接高并发 |
| TLS 要求 | 可选 | 实践中必须 HTTPS |
如何启用 HTTP/2
HTTP/2 需要 HTTPS(主流浏览器仅对 TLS 启用 h2)。在宝塔面板/Nginx 中:
# nginx 配置
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /path/cert.pem;
ssl_certificate_key /path/key.pem;
宝塔面板中:网站 → SSL → 开启 HTTPS 后,通常自动启用 HTTP/2。
验证是否启用
curl -I --http2 https://www.example.com
# HTTP/2 200 ← 协议版本显示 HTTP/2 即生效
HTTP/3 基于 QUIC(UDP),进一步解决 TCP 层面的队头阻塞,Google、Facebook 等已大规模使用,未来会逐步普及。
SSL 免费证书
让网站启用 HTTPS 需要一张 SSL/TLS 证书。本节介绍证书的类型,以及如何免费获取——对个人站长来说,Let's Encrypt 是首选。
什么是 SSL 证书
SSL 证书是一份由证书颁发机构(CA)签发的数字文件,包含网站公钥、域名、颁发者、有效期等信息,用于证明"这个网站确实是它声称的那个网站"。
证书类型
| 类型 | 验证级别 | 适用场景 |
|---|---|---|
| DV(域名验证) | 验证域名所有权 | 个人网站、博客(免费) |
| OV(组织验证) | 验证企业身份 | 企业官网 |
| EV(扩展验证) | 严格企业审核 | 金融、支付等高信任场景 |
免费证书方案
| 方案 | 有效期 | 特点 |
|---|---|---|
| Let's Encrypt | 90 天 | 免费、自动续期、社区标准 |
| ZeroSSL | 90 天 | 免费、支持多域名 |
| 腾讯云/阿里云免费证书 | 90 天-1 年 | 国内访问稳定,需手动申请 |
宝塔面板一键申请(推荐)
- 宝塔面板 → 网站 → 选择站点 → SSL
- 选择 Let's Encrypt,勾选域名
- 点击"申请",面板自动完成验证与部署
- 开启"自动续期",到期前自动更新
整个过程无需命令行,几分钟搞定。
手动方式(acme.sh)
# 安装 acme.sh(Let's Encrypt 客户端)
curl https://get.acme.sh | sh
# 签发证书(HTTP 验证)
acme.sh --issue -d www.example.com -w /www/wwwroot/example
# 安装证书到指定目录
acme.sh --install-cert -d www.example.com --key-file /path/key.pem --fullchain-file /path/cert.pem
证书验证与续期
# 查看证书到期时间
echo | openssl s_client -connect www.example.com:443 2>/dev/null | openssl x509 -noout -dates
# 手动续期(acme.sh 默认自动)
acme.sh --renew -d www.example.com
免费证书通常每 90 天到期,务必开启自动续期,否则到期后网站会出现证书错误,访问被浏览器拦截。