HTTP(超文本传输协议)是互联网的基石,而 HTTPS 是其安全增强版。作为前端工程师,深入理解两者的区别和工作原理,对排查问题、性能优化和安全防护都至关重要。
一、HTTP 基础
1.1 请求 - 响应模型
HTTP 遵循简单的请求 - 响应模式:客户端发送请求,服务器返回响应。
客户端(浏览器) 服务器
| |
| --- GET /api/users HTTP/1.1 ---> |
| |
| <--- HTTP/1.1 200 OK ------- |
| Content-Type: application/json |
| [{"id":1, "name":"Alice"}] |1.2 HTTP 请求方法
| 方法 | 语义 | 幂等性 | 安全性 | 常见场景 |
|---|---|---|---|---|
GET |
获取资源 | ✅ 幂等 | ✅ 安全 | 查询数据、页面访问 |
POST |
创建资源 | ❌ 非幂等 | ❌ 不安全 | 表单提交、登录 |
PUT |
全量更新 | ✅ 幂等 | ❌ 不安全 | 替换整个资源 |
PATCH |
部分更新 | ❌ 非幂等 | ❌ 不安全 | 修改部分字段 |
DELETE |
删除资源 | ✅ 幂等 | ❌ 不安全 | 删除数据 |
HEAD |
获取响应头 | ✅ 幂等 | ✅ 安全 | 检查资源是否存在 |
OPTIONS |
查询支持的方法 | ✅ 幂等 | ✅ 安全 | CORS 预检请求 |
// 前端使用 Fetch API 示例
// GET
const users = await fetch('/api/users').then(r => r.json());
// POST
const newUser = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Bob', email: 'bob@example.com' }),
}).then(r => r.json());
// PUT
await fetch('/api/users/1', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Bob Updated', email: 'bob@example.com' }),
});
// DELETE
await fetch('/api/users/1', { method: 'DELETE' });1.3 HTTP 状态码
| 状态码范围 | 类别 | 常见状态码 |
|---|---|---|
1xx |
信息响应 | 100 Continue、101 Switching Protocols |
2xx |
成功 | 200 OK、201 Created、204 No Content |
3xx |
重定向 | 301 Moved Permanently、302 Found、304 Not Modified |
4xx |
客户端错误 | 400 Bad Request、401 Unauthorized、403 Forbidden、404 Not Found、429 Too Many Requests |
5xx |
服务器错误 | 500 Internal Server Error、502 Bad Gateway、503 Service Unavailable、504 Gateway Timeout |
// 前端状态码处理最佳实践
async function apiRequest(url, options = {}) {
const response = await fetch(url, options);
if (!response.ok) {
switch (response.status) {
case 401:
// 跳转登录
window.location.href = '/login';
throw new Error('未授权,请重新登录');
case 403:
throw new Error('没有访问权限');
case 404:
throw new Error('请求的资源不存在');
case 429:
// 等待后重试
const retryAfter = response.headers.get('Retry-After') || 5;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return apiRequest(url, options);
case 500:
throw new Error('服务器内部错误,请稍后重试');
default:
throw new Error(`请求失败: ${response.status}`);
}
}
return response.json();
}1.4 HTTP 的致命缺陷:明文传输
HTTP 最大的问题是所有数据都以明文传输。这意味着:
- 窃听风险:同一 Wi-Fi 下的任何人都能抓包看到你的密码、银行卡号
- 篡改风险:中间人可以修改传输内容(中间人攻击),插入恶意广告或脚本
- 冒充风险:无法验证对方是否是真的服务器
HTTP 明文传输示例(抓包可见):
GET /login HTTP/1.1
Host: bank.example.com
HTTP/1.1 200 OK
...
<form action="/login" method="POST">
<input name="username" value="alice">
<input name="password" value="mysecret123"> ← 密码明文可见!
</form>二、HTTPS = HTTP + TLS
HTTPS 在 HTTP 和 TCP 之间插入 TLS(Transport Layer Security) 层,提供:
- 加密(Encryption):数据加密传输,无法窃听
- 完整性(Integrity):数据无法被篡改
- 身份验证(Authentication):验证服务器身份
HTTP: [HTTP] → [TCP] → [IP]
HTTPS: [HTTP] → [TLS] → [TCP] → [IP]
↑
加密/认证层2.1 TLS 握手过程(简化版)
客户端 (浏览器) 服务器 (website.com)
| |
| ① ClientHello |
| (支持的 TLS 版本、加密套件列表) |
| ----------------------------------> |
| |
| ② ServerHello |
| (选定的 TLS 版本、加密套件) |
| ③ Certificate |
| (服务器 SSL 证书,含公钥) |
| ④ ServerHelloDone |
| <---------------------------------- |
| |
| ⑤ 验证证书链 |
| ⑥ 生成 Premaster Secret |
| ⑦ ClientKeyExchange |
| (用服务器公钥加密的 Premaster Secret) |
| ----------------------------------> |
| |
| ⑧ 双方用 Premaster Secret |
| 生成对称加密的 Session Key |
| |
| ←======= 后续通信 ========→ |
| (使用 Session Key 对称加密) |关键点:
- 非对称加密(RSA/ECDHE):仅在握手阶段使用,用于安全交换对称密钥。公钥加密、私钥解密,计算开销大。
- 对称加密(AES/ChaCha20):握手完成后用于加密数据传输。速度快,适合大量数据。
- 为什么不全程用非对称加密? —— 太慢了,性能不可接受。对称加密速度快数百倍。
2.2 证书链验证
根 CA 证书(Root CA)
└── 中间 CA 证书(Intermediate CA)
└── 网站证书(example.com)
浏览器验证流程:
1. 检查网站证书是否由受信任的中间 CA 签发
2. 检查中间 CA 证书是否由受信任的根 CA 签发
3. 检查证书是否在有效期内
4. 检查证书的域名是否匹配
5. 检查证书是否被吊销(OCSP / CRL)2.3 中间人攻击(MITM)与 HTTPS 的防护
HTTP 下的 MITM 攻击(可被攻击):
用户 ←→ 攻击者(咖啡店 Wi-Fi 热点)←→ 真实服务器
↑ 攻击者可以看到、修改所有数据
HTTPS 下的防护:
用户 ←→ 攻击者 ←→ 真实服务器
↑ 攻击者无法解密(无服务器私钥)
↑ 攻击者无法伪造证书(无受信任 CA 签名)三、为什么要全站 HTTPS?
3.1 浏览器强制策略
- Chrome/Firefox/Safari 对 HTTP 页面标记"不安全"
- HTTP/2 浏览器实现只支持 HTTPS
- 许多新 Web API 仅在安全上下文(HTTPS 或 localhost)可用:
navigator.geolocation(地理位置)navigator.mediaDevices.getUserMedia()(摄像头/麦克风)- Service Workers
- Push API
- Payment Request API
3.2 SEO 优势
Google 明确将 HTTPS 作为排名信号。HTTPS 网站的搜索排名优于同等情况下的 HTTP 网站。
3.3 Referrer 信息保留
从 HTTPS 页面跳转到 HTTP 页面时,浏览器不会发送 Referrer 头(防止信息泄露),可能影响统计分析。
四、HTTPS 性能与优化
| 优化项 | 说明 | 效果 |
|---|---|---|
| TLS 1.3 | 握手减少为 1-RTT(往返一次) | 比 TLS 1.2 快 30-50% |
| HTTP/2 / HTTP/3 | 多路复用、头部压缩 | 显著减少延迟 |
| OCSP Stapling | 服务器提前获取 OCSP 响应 | 减少客户端验证延迟 |
| Session Resumption | 复用之前的 TLS 会话 | 0-RTT 恢复连接 |
| HSTS | 强制浏览器只用 HTTPS | 消除 301 重定向开销 |
# Nginx HTTPS 优化配置示例
server {
listen 443 ssl http2;
server_name example.com;
# 证书路径
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
# 只用 TLS 1.2 和 1.3
ssl_protocols TLSv1.2 TLSv1.3;
# 优先服务器端加密套件
ssl_prefer_server_ciphers on;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
# Session 缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS(一年,包含子域名)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}五、免费获取 HTTPS 证书
Let's Encrypt + Certbot
# 1. 安装 Certbot(Ubuntu/Debian)
sudo apt update && sudo apt install certbot python3-certbot-nginx
# 2. 自动获取并配置证书(Nginx 示例)
sudo certbot --nginx -d example.com -d www.example.com
# 3. 设置自动续期
sudo certbot renew --dry-run # 测试
# Certbot 默认添加 crontab 自动续期
# 4. 手动续期(证书有效期 90 天)
sudo certbot renew其他免费证书选择:
| 提供商 | 特点 | 有效期 |
|---|---|---|
| Let's Encrypt | 最流行,自动化 | 90 天 |
| ZeroSSL | 支持 REST API | 90 天 |
| Cloudflare | CDN 自带免费证书 | 自动续期 |
| BuyPass | 180 天,仅欧洲 | 180 天 |
六、HTTP vs HTTPS 全面对比
| 维度 | HTTP | HTTPS |
|---|---|---|
| 端口 | 80 | 443 |
| 加密 | ❌ 明文 | ✅ TLS 加密 |
| 身份验证 | ❌ 无 | ✅ SSL 证书 |
| 数据完整性 | ❌ 无保证 | ✅ 有保证 |
| 速度 | 略快(无加密开销) | TLS 1.3 下几乎无差别 |
| SEO | ❌ 降权 | ✅ 提权 |
| 浏览器标签 | "不安全" | 🔒 安全锁 |
| Web API 可用性 | 受限 | 完整 |
| 证书成本 | 免费 | 免费(Let's Encrypt) |
| HTTP 版本支持 | HTTP/1.1 | HTTP/1.1, HTTP/2, HTTP/3 |
| 推荐 | ❌ 不推荐 | ✅ 必须 |
七、总结
- HTTP 是明文传输,存在窃听、篡改、冒充三大风险
- HTTPS = HTTP + TLS,通过非对称加密交换密钥、对称加密传输数据
- TLS 1.3 已将握手简化为 1-RTT,性能几乎无影响
- 全站 HTTPS 是 Web 标准:浏览器强制、SEO 加分、新 API 硬性要求
- Let's Encrypt 免费证书让 HTTPS 零成本部署
作为前端开发,无论你是自己部署服务还是对接后端 API,请务必优先使用 HTTPS。在本地开发时,可以使用 mkcert 生成自签名证书来模拟 HTTPS 环境。
# 本地开发 HTTPS 环境
brew install mkcert # macOS
mkcert -install
mkcert localhost 127.0.0.1
# 生成 localhost+1.pem 和 localhost+1-key.pem