Skip to content

[L1] HTTP 301、302、307 重定向状态码有什么语义差异?如何选择?

一句话结论

301 永久重定向(可缓存、允许方法变更),302 临时重定向(历史实现允许方法变更),307 严格临时重定向(强制保持原请求方法),选型依据是"是否永久"和"是否需要保持 POST 方法"。

体系讲解

核心对比

状态码语义是否可被缓存方法是否可变典型场景
301 Moved Permanently永久迁移✅ 可缓存(浏览器/CDN 长期记住)⚠️ 允许变为 GETHTTP → HTTPS、域名变更、旧 URL 规范化
302 Found临时重定向❌ 默认不缓存⚠️ 允许变为 GET(历史行为)登录后跳转、A/B 测试、临时维护页
307 Temporary Redirect临时重定向(严格)❌ 默认不缓存✅ 必须保持原方法API 临时迁移(POST 表单、REST API)

方法变更的历史问题

HTTP/1.0 规范要求:对 301/302 响应,若原请求为 POST,重定向后应继续使用 POST。但早期浏览器实现将 POST 重定向后改为 GET,这一错误行为后来被事实标准化。307 正是为了弥补这一缺口,在 HTTP/1.1 中明确语义:无论原方法是什么,307 必须保持原方法重放请求

308 Permanent Redirect

308 是 301 的严格版本:永久迁移 + 强制保持原方法,对应 307 与 302 的关系。

临时 vs 永久     允许方法变更    强制保持方法
  302                302              307
  301                301              308

SEO 与缓存影响

  • 301:搜索引擎将链接权重(PageRank)转移到新 URL,浏览器长期缓存;使用后如需撤销,缓存清除困难。
  • 302/307:搜索引擎保留原 URL 的权重,适合临时跳转。

考察意图

  • 考察候选人是否理解 HTTP 重定向状态码的语义差异
  • 验证是否了解 POST 重定向场景下 302 与 307 的行为差异
  • 检验是否能根据"永久/临时"、"方法保持"两个维度进行正确选型

追问链

  1. 用户提交表单(POST)后,服务器希望跳转到结果页,应该用哪个状态码?

    简答:应用 303 See Other(POST/Redirect/GET 模式)。303 明确指示客户端用 GET 方法访问目标 URL,是 Web 表单防止"刷新重复提交"的标准做法。302 虽然实践中行为相同,但语义上 303 更精确。

  2. 如果将 HTTP 全站重定向到 HTTPS,用 301 还是 302?为什么?

    简答:用 301。HTTP → HTTPS 是永久迁移,301 告知浏览器和搜索引擎永久记住新地址,浏览器后续直接访问 HTTPS,减少一次 HTTP 请求;302 每次都会发起 HTTP 请求再跳转,不利于安全(首次请求仍为明文)。配合 HSTS 效果更佳。

  3. 301 重定向的缓存有什么潜在风险?

    简答:301 默认被浏览器永久缓存(无需服务器介入),一旦发出后若需要撤销,用户必须手动清除缓存才能看到变更。因此对于不确定是否永久的跳转,应优先用 302/307,待确认后再改为 301。

易错点

  1. 用 302 重定向 POST 请求却期望保持 POST:浏览器遇到 302 会将 POST 改为 GET 重放(历史行为),若 API 迁移需要保持 POST 方法,必须使用 307。

  2. 混淆 302 与 303 的表单重定向:表单提交后的重定向应使用 303(POST/Redirect/GET 模式),而非 302。虽然浏览器对二者行为相同,但 303 语义更清晰,且明确禁止重放 POST,是规范用法。

  3. 随意使用 301 导致难以回滚:301 会被浏览器长期缓存,若业务变动需要撤销跳转,已缓存的客户端无法感知。在正式切换前应先用 302 验证跳转逻辑,再改为 301。

代码示例

php
<?php
// 301:永久重定向(HTTP → HTTPS 全站迁移)
function redirectPermanent(string $url): never
{
    header('Location: ' . $url, true, 301);
    exit;
}

// 302:临时重定向(登录跳转、A/B 测试)
function redirectTemporary(string $url): never
{
    header('Location: ' . $url, true, 302);
    exit;
}

// 307:临时重定向,保持原请求方法(API 临时迁移)
function redirectTemporaryStrict(string $url): never
{
    header('Location: ' . $url, true, 307);
    exit;
}

// 303:POST/Redirect/GET 模式(表单提交后跳转结果页)
function redirectAfterPost(string $url): never
{
    header('Location: ' . $url, true, 303);
    exit;
}

// 使用示例
$method = $_SERVER['REQUEST_METHOD'];

if ($method === 'GET' && !isset($_SERVER['HTTPS'])) {
    // HTTP 全站跳 HTTPS → 301
    redirectPermanent('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
}

if ($method === 'POST' && isset($_POST['form_data'])) {
    // 表单处理完毕 → 303 跳转结果页
    redirectAfterPost('/result?id=123');
}

基于 Apache License 2.0 开源