HTTP 狀態碼是伺服器回應客戶端請求時所使用的標準代碼,其中 3xx 代表重新導向(Redirection)。它通常表示目前請求的資源位於其他位置,或客戶端需要進一步操作才能完成請求。
在網站開發與 SEO 中,最常見的重新導向狀態碼包括 301、302、303、307、308,另外還有較少直接用於網址跳轉的 300 與 304。
3xx 狀態碼比較
| 狀態碼 | 名稱 | 主要用途 | 性質 |
|---|---|---|---|
| 300 | Multiple Choices | 同一資源有多個版本可選 | 多重選擇 |
| 301 | Moved Permanently | 網址永久搬遷 | 永久重新導向 |
| 302 | Found | 網址暫時搬遷 | 暫時重新導向 |
| 303 | See Other | POST 完成後前往另一頁查看結果 | 改用 GET |
| 304 | Not Modified | 資源沒有修改,可使用快取 | 快取控制 |
| 307 | Temporary Redirect | 暫時搬遷並保留 HTTP Method | 暫時重新導向 |
| 308 | Permanent Redirect | 永久搬遷並保留 HTTP Method | 永久重新導向 |
300 Multiple Choices
300 Multiple Choices 表示同一個請求可能對應多個不同的資源,例如同一份文件同時存在 HTML、PDF、中文版或英文版。伺服器可以回傳多個選擇,讓客戶端自行決定要使用哪一個版本。
這種狀態在一般網站中並不常見。現在多數網站會透過程式邏輯、語言設定或內容協商直接決定要提供哪個版本,而不是讓使用者透過 300 狀態碼選擇。
從 SEO 角度來看,如果網站存在多個相似內容頁面,通常會使用 Canonical、hreflang 或 Redirect 等方式處理,而不是依賴 300。
301 Moved Permanently
301 Moved Permanently 表示原本的資源已經永久移動到新的 URL。
例如:
https://example.com/old-page
永久更改為:
https://example.com/new-page
伺服器可以回傳:
HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-page
301 是網站最常見的 Redirect 類型,適合用於更換網域、HTTP 轉 HTTPS、www 與非 www 統一、文章網址修改、網站目錄結構調整,以及舊頁面永久移動到新頁面的情況。
在 SEO 上,搜尋引擎會逐步把舊 URL 的搜尋訊號轉移到新的 URL,因此網站永久搬遷時通常會使用 301。不過不應簡化成「搜尋權重一定 100% 完整轉移」,實際結果仍會受到頁面內容、Canonical、內部連結、Sitemap 與 Redirect Chain 等因素影響。
301 有一個需要注意的地方:歷史上部分瀏覽器或 HTTP Client 在處理 POST 請求時,可能在 Redirect 後把 POST 改成 GET。如果必須確保原本的 HTTP Method 不變,則應考慮使用 308。
302 Found
302 Found 表示資源目前暫時位於另一個 URL,但原本的 URL 並沒有被永久取代。
例如網站有一個產品頁:
/product
活動期間暫時導向:
/product/summer-sale
就可以使用 302,活動結束後再取消 Redirect。
302 常見於短期活動、維護頁面、A/B Testing、地區導向、登入流程或其他暫時性的頁面切換。
SEO 上,302 傳達的是「原網址只是暫時離開」,因此搜尋引擎通常仍會把原 URL 視為主要網址。不過如果一個 302 長期存在,搜尋引擎也可能根據實際情況重新判斷其性質。
302 和 301 一樣存在 HTTP Method 的歷史相容性問題,因此如果需要保證 POST、PUT 或 PATCH 在 Redirect 後仍維持相同 Method,可以改用 307。
303 See Other
303 See Other 最常出現在表單提交或建立資料之後。它的意思是目前請求已經處理完成,客戶端應該使用 GET 前往另一個 URL 查看結果。
例如:
POST /orders
伺服器建立訂單後回傳:
HTTP/1.1 303 See Other
Location: /orders/123
瀏覽器接下來會:
GET /orders/123
這就是常見的 Post / Redirect / Get(PRG) 模式。
這種方式可以避免使用者在完成表單、留言、付款或建立資料後重新整理頁面時,再次送出相同 POST 請求。
304 Not Modified
304 Not Modified 雖然屬於 3xx,但它並不是一般意義上的網址重新導向,而是 HTTP Cache 機制的一部分。
例如瀏覽器之前已經下載過:
style.css
再次請求時可以附帶:
If-None-Match
或:
If-Modified-Since
如果伺服器確認檔案沒有修改,就可以回傳:
HTTP/1.1 304 Not Modified
此時瀏覽器不需要重新下載完整內容,可以直接使用本地快取,因此能降低流量並提高網站載入速度。
304 常見於 CSS、JavaScript、圖片與其他靜態資源。
307 Temporary Redirect
307 Temporary Redirect 和 302 都代表暫時重新導向,但 307 對 HTTP Method 的規則更明確。
例如原本是:
POST /api/order
收到:
HTTP/1.1 307 Temporary Redirect
Location: /api/order-new
客戶端重新請求時仍然必須使用:
POST /api/order-new
因此 307 特別適合 API、POST、PUT、PATCH 或其他不能隨意改變 HTTP Method 的請求。
簡單來說,302 表示「暫時換網址」,307 則表示「暫時換網址,而且原本的請求方式不能改」。
308 Permanent Redirect
308 Permanent Redirect 與 301 類似,都表示資源已經永久搬遷,但 308 要求 HTTP Method 與 Request Body 必須保留。
例如:
POST /api/v1/order
永久搬到:
POST /api/v2/order
就可以使用:
HTTP/1.1 308 Permanent Redirect
Location: /api/v2/order
因此 308 很適合 API Endpoint 永久搬遷,而一般網頁網址永久調整仍最常使用 301。
301 與 308 的差異
301 與 308 都屬於永久重新導向。主要差異不在 SEO,而是在 HTTP Method 的處理方式。
| 狀態碼 | 永久 Redirect | 保留原 HTTP Method |
|---|---|---|
| 301 | 是 | 不一定 |
| 308 | 是 | 是 |
一般文章或網站頁面永久改網址通常使用 301;如果是 API,且需要確保 POST、PUT、PATCH 等 Method 完整保留,則 308 更適合。
302 與 307 的差異
302 與 307 都屬於暫時重新導向,同樣主要差異在 HTTP Method。
| 狀態碼 | 暫時 Redirect | 保留原 HTTP Method |
|---|---|---|
| 302 | 是 | 不一定 |
| 307 | 是 | 是 |
一般網站臨時活動頁面使用 302 已經足夠;API 或需要保留 Request Body 的請求則較適合使用 307。
重新導向與 SEO
網站修改 URL 時,Redirect 是非常重要的一環。
例如:
http://example.com
→
https://example.com
或者:
https://example.com/old-page
→
https://example.com/new-page
如果這些修改是永久性的,通常使用 301。
除了設定 Redirect,也應同步修改網站內部連結、Canonical 與 Sitemap。不要讓網站內部連結長期指向舊網址,再依靠 301 前往新網址。
例如不理想:
首頁
↓
舊網址
↓ 301
新網址
較好的方式是直接修改成:
首頁
↓
新網址
Redirect Chain
Redirect 不宜經過太多層。
例如:
A
↓ 301
B
↓ 301
C
↓ 301
D
如果 A 最終就是要到 D,最好直接設定:
A
↓ 301
D
過多的 Redirect Chain 會增加 HTTP Request、網站載入時間與搜尋引擎 Crawl 成本,也會讓日後維護更加複雜。
Redirect Loop
設定錯誤時可能出現 Redirect Loop,例如:
A → B
B → A
瀏覽器會不斷在兩個 URL 之間跳轉,最後出現:
Too Many Redirects
網站同時使用 Cloudflare、Nginx、Apache、WordPress 或其他 Reverse Proxy 時尤其容易發生這類問題,因為每一層都可能各自設定 HTTP、HTTPS 或網域 Redirect。
Redirect 與 Canonical
Redirect 和 Canonical 的作用並不完全相同。
Redirect 表示:
舊網址已經不應繼續使用
→ 前往新網址
Canonical 則表示:
這個網址仍然存在
→ 但搜尋引擎應把另一個網址視為主要版本
例如:
<link rel="canonical" href="https://example.com/page">
如果頁面真的已經永久搬遷,應使用 301;如果多個 URL 都需要保留,只是內容高度相似,則可以考慮使用 Canonical。
Redirect 與 Sitemap
Sitemap 應直接列出網站希望搜尋引擎索引的最終 URL。
例如:
/old-page
↓ 301
/new-page
Sitemap 應放:
/new-page
而不是繼續列出:
/old-page
同樣地,網站內部連結也應逐步修改成最終 URL,而不是長期依賴 Redirect。
Nginx 設定範例
HTTP 永久導向 HTTPS:
return 301 https://example.com$request_uri;
單一頁面永久 Redirect:
location = /old-page {
return 301 /new-page;
}
暫時 Redirect:
return 302 https://example.com/temporary;
Apache 設定範例
使用 .htaccess:
Redirect 301 /old-page https://example.com/new-page
也可以使用:
RewriteEngine On
RewriteRule ^old-page$ /new-page [R=301,L]
PHP 設定範例
301:
header('Location: https://example.com/new-page', true, 301);
exit;
302:
header('Location: https://example.com/temporary', true, 302);
exit;
303:
header('Location: /result', true, 303);
exit;
Laravel 設定範例
一般 Redirect:
return redirect('/new-page');
一般情況下會使用 302。
永久 Redirect:
return redirect()->to('/new-page', 301);
ASP.NET Core 設定範例
暫時 Redirect:
return Redirect("/new-page");
永久 Redirect:
return RedirectPermanent("/new-page");
如果需要保留 HTTP Method,可以使用:
return RedirectPreserveMethod("/new-page");
永久並保留 Method:
return RedirectPermanentPreserveMethod("/new-page");
JavaScript Redirect
JavaScript 也可以執行頁面跳轉:
window.location.href = '/new-page';
但這和 HTTP Redirect 不完全相同。
HTTP Redirect 是伺服器直接回傳:
Request
↓
301 / 302
↓
新網址
JavaScript Redirect 則必須先下載 HTML,再執行 JavaScript:
Request
↓
HTML
↓
JavaScript 執行
↓
新網址
因此如果是網站搬遷或 SEO 用途,通常應優先使用伺服器端的 301、302、307 或 308。
如何選擇狀態碼
最簡單的判斷方式如下:
| 情況 | 建議狀態碼 |
|---|---|
| 網頁永久改網址 | 301 |
| 網頁暫時改網址 | 302 |
| POST 完成後前往結果頁 | 303 |
| 暫時 Redirect 且 Method 不可改 | 307 |
| 永久 Redirect 且 Method 不可改 | 308 |
| 資源沒有修改,使用快取 | 304 |
一般網站開發最常遇到的是 301 與 302,而在 API 開發中則需要特別理解 307 與 308。
可以簡單記成:
301 = 永久搬家
302 = 暫時搬家
303 = 處理完成後用 GET 看結果
307 = 暫時搬家,但 Method 不變
308 = 永久搬家,但 Method 不變
正確選擇 Redirect 狀態碼,不只會影響瀏覽器的行為,也會影響 API、快取、搜尋引擎索引與網站長期維護,因此應依「是否永久」以及「HTTP Method 是否需要保留」來決定。