Mã HTTP 302 (302 Found) là gì? Lỗi 302 và 302 vs 301
Điểm chính
HTTP 302 Found là chuyển hướng tạm thời, không phải lỗi: máy chủ cho biết trang hiện nằm ở một URL khác, được nêu trong header Location. Trình duyệt tải ngay URL đó, còn liên kết và công cụ tìm kiếm vẫn giữ URL gốc. Dùng 301 hoặc 308 khi việc dời trang là vĩnh viễn: trong 20 trang web lớn chúng tôi kiểm tra, không trang nào dùng 302 cho việc đó. Bạn thường gặp 302 khi một trang yêu cầu đăng nhập. Khi theo 302, trình duyệt đổi POST thành GET: dùng 307 để giữ nguyên phương thức, hoặc 303 sau một biểu mẫu.
Kiểm tra ngay

Bắt đầu đọc
- Mã trạng thái 302 là gì?
- Cấu trúc của một phản hồi 302
- Vì sao tôi nhận 302 thay vì 200?
- 302 vs 301 vs 307 vs 308: nên dùng chuyển hướng nào?
- Khi nào nên dùng chuyển hướng 302?
- Cách gửi mã trạng thái 302
- Cách kiểm tra mã trạng thái 302
- Chuyển hướng 302 và SEO
- Vì sao 302 biến yêu cầu POST thành GET
- Các lỗi 302 thường gặp và cách sửa
- Vòng lặp chuyển hướng 302: cách chẩn đoán
- Thực hành tốt nhất với mã trạng thái 302
- Trình duyệt và công cụ xử lý 302 như thế nào
- Câu Hỏi Thường Gặp
Mã trạng thái 302 là gì?
HTTP 302 Found là chuyển hướng tạm thời. Máy chủ trả lời "thứ bạn yêu cầu tạm thời nằm ở nơi khác" và nêu URL kia trong header Location. Trình duyệt tải ngay URL đó, nhưng dấu trang, liên kết và công cụ tìm kiếm vẫn nên dùng URL gốc (RFC 9110 §15.4.3).
Chữ "tạm thời" đó chính là điểm khác biệt duy nhất với 301 Moved Permanently, mã cho biết URL cũ đã mất hẳn. HTTP/1.0 gọi 302 là "Moved Temporarily" (RFC 1945); năm 1999, RFC 2616 đổi tên thành "Found", nhưng ý nghĩa không đổi.
Là người truy cập, bạn hiếm khi thấy 302, vì trình duyệt theo nó trước khi có gì hiện ra. Bạn gặp nó trong DevTools, curl, các ứng dụng gọi API và các bản kiểm tra SEO.
Xem mọi chuyển hướng và mã trạng thái của chúng
Cấu trúc của một phản hồi 302
Một phản hồi 302 rất nhỏ. Các thành phần của nó:
- Dòng trạng thái —
HTTP/1.1 302 Found, hoặc chỉHTTP/2 302(HTTP/2 không có cụm từ lý do) - Location — URL cần chuyển tới. RFC 9110 nói máy chủ SHOULD (nên) gửi nó; nếu thiếu, trình duyệt không có nơi để đi và hiển thị phần thân của chính 302, thường là trang trống
- Phần thân — RFC 9110 nói nó "thường chứa một ghi chú siêu văn bản ngắn" kèm liên kết. Trình duyệt bỏ qua nó; nginx, Apache và Express mặc định gửi ghi chú một dòng, còn nhiều trang lớn gửi phần thân trống
- Header cache — không cần. Trình duyệt không cache 302 trừ khi bạn thêm
Cache-Control: max-agehoặcExpires; ngược lại, 301 và 308 được cache theo mặc định. CDN vẫn có thể cache nó (xem "302 bị kẹt" bên dưới)
HTTP/1.1 302 Found
Location: https://www.example.com/login?next=%2Fdashboard
Content-Length: 0
Date: Mon, 26 Oct 2026 14:00:00 GMTLocation có thể là một URL đầy đủ hoặc một đường dẫn tương đối như /login: RFC 9110 cho phép mọi URI reference, và trình duyệt phân giải nó dựa trên URL đã yêu cầu. Trong mã ứng dụng (ví dụ Express), đường dẫn tương đối tránh làm lộ tên máy chủ nội bộ hoặc http:// từ phía sau proxy; còn nginx và Apache vẫn biến nó thành URL tuyệt đối, trừ khi bạn đặt absolute_redirect off hoặc RedirectRelative On.
Vì sao tôi nhận 302 thay vì 200?
Vì trang cần thứ mà yêu cầu của bạn không mang theo, hoặc URL bạn dùng không phải URL mà trang web phục vụ. Các lý do thường gặp:
- Bạn chưa đăng nhập — các trang sau màn hình đăng nhập trả 302 về trang đăng nhập, kèm trang bạn muốn trong một tham số quay lại. Khi chưa đăng nhập,
github.com/settingsđưa bạn tới/login?return_to=…. Trong curl hoặc ứng dụng gọi API, hãy gửi cookie phiên hoặc token. - Ứng dụng của bạn không theo chuyển hướng — trình duyệt,
fetch()và Python requests tự động theo. curl thì không, trừ khi bạn thêm-L; nó dừng ở 302 và chỉ in phần thân của nó, thường là trống (thêm-iđể xem trạng thái và Location). - URL không phải URL mà trang web phục vụ — thiếu hoặc thừa dấu gạch chéo ở cuối, một đường dẫn ngôn ngữ, hoặc một liên kết theo dõi đẩy bạn đi tiếp.
res.redirect()của Express,returnchỉ có URL của nginx vàRedirectcủa Apache đều gửi 302 nếu không chỉ định khác. - Có thứ gì đó phía trước máy chủ thêm vào — nếu máy chủ gốc trả 200 khi bạn thử trực tiếp nhưng URL công khai trả 302, thì một quy tắc của CDN, bộ cân bằng tải hoặc proxy đang chuyển hướng.
API thường trả 401 Unauthorized khi thiếu đăng nhập thay vì chuyển hướng. Để xem mọi bước và mã trạng thái của chúng, hãy chạy URL qua Kiểm tra Redirect.
302 vs 301 vs 307 vs 308: nên dùng chuyển hướng nào?
Năm mã chuyển hướng bao phủ gần như mọi trường hợp. Chúng khác nhau ở hai điểm: việc dời có vĩnh viễn không, và POST có giữ nguyên là POST không:
| Mã | Vĩnh viễn? | POST trong trình duyệt | Cache theo mặc định? | Phù hợp nhất cho |
|---|---|---|---|---|
| 301 Moved Permanently | Có | Thành GET | Có | Đổi URL vĩnh viễn, chuyển tên miền |
| 302 Found | Không | Thành GET | Không | Đăng nhập, dời ngắn hạn, A/B test |
| 303 See Other | Không | Thành GET | Không | Trang hiển thị sau khi gửi biểu mẫu |
| 307 Temporary Redirect | Không | Giữ POST | Không | Dời tạm thời cần giữ nguyên phương thức |
| 308 Permanent Redirect | Có | Giữ POST | Có | Dời vĩnh viễn cần giữ nguyên phương thức |
303 và 307 tồn tại là vì 302. HTTP/1.1 thêm 303 vào năm 1997, và năm 1999 RFC 2616 thừa nhận rằng "hầu hết các bản cài đặt user agent hiện có xử lý 302 như thể đó là phản hồi 303", thêm 307 và đổi tên 302 thành "Found" (RFC 2616 §10.3.3). Nếu một chuyển hướng tạm thời có thể nhận POST, hãy dùng 307 để giữ nó, hoặc 303 để tải trang tiếp theo bằng GET.
Khi nào nên dùng chuyển hướng 302?
Dùng 302 khi bạn dự kiến chuyển hướng sẽ biến mất. Các trường hợp điển hình:
- Chuyển hướng đăng nhập — đưa người dùng chưa đăng nhập từ
/dashboardsang/login, rồi quay lại sau khi đăng nhập - A/B test — gửi một số khách truy cập tới một trang biến thể; lời khuyên về thử nghiệm của chính Google là dùng 302, không phải 301, ở đây (Google Search Central)
- Trang đang sửa — đưa khách tới một trang thông báo trong vài ngày trong lúc xây lại trang
- URL chiến dịch ngắn hạn —
/black-fridaytrỏ tới trang khuyến mãi của năm nay chỉ trong thời gian khuyến mãi - Bảo trì — chỉ dành cho khách truy cập; với công cụ tìm kiếm, câu trả lời tốt hơn khi ngừng hoạt động theo kế hoạch là 503 kèm Retry-After
Nếu bất kỳ trường hợp nào trong số này trở thành vĩnh viễn, hãy đổi sang 301.
Cách gửi mã trạng thái 302
Hầu hết máy chủ và framework đều có cách gửi 302 chỉ bằng một dòng. Mỗi cách dưới đây gửi 302 Found kèm header Location, tất cả những gì một 302 cần.
Nginx
Trong nginx, dùng return kèm mã. return chỉ có URL cũng gửi 302 (tài liệu nginx):
server {
listen 80;
server_name example.com;
# Temporary redirect (302 Found)
location /old-page {
return 302 https://example.com/new-page;
}
}Apache (.htaccess)
Trong Apache, dùng Redirect (302 là mặc định khi bạn không đưa ra trạng thái) hoặc RewriteRule với [R=302,L]:
# Simple temporary redirect
Redirect 302 /old-page https://example.com/new-page
# Or with mod_rewrite for pattern matching
RewriteEngine On
RewriteRule ^maintenance$ /maintenance.html [R=302,L]Node.js (Express)
res.redirect() của Express mặc định dùng 302 khi không truyền mã trạng thái:
// Temporary redirect (302 Found by default)
app.get('/dashboard', (req, res) => {
if (!req.user) {
return res.redirect('/login') // sends 302
}
// ...render dashboard
})
// Or be explicit:
res.redirect(302, '/login')Cách kiểm tra mã trạng thái 302
Cách kiểm tra nhanh nhất là curl trong terminal: nó hiển thị mã trạng thái và header Location mà không bị cache của trình duyệt xen vào.
# Status and headers, without following the redirect
curl -sI https://example.com/old-page
# -I sends HEAD, which some servers answer differently; this sends a real GET
curl -s -o /dev/null -D - https://example.com/old-page
# Expected:
# HTTP/2 302
# location: https://example.com/new-page
# Follow the whole chain and print each hop's status and Location
curl -sL -o /dev/null -D - https://example.com/old-page | grep -iE '^(HTTP/|location:)'Không có terminal? Kiểm tra Redirect của DNS Robot theo từng bước (301, 302, 303, 307, 308 và meta refresh) từ máy chủ của chúng tôi và hiển thị từng mã trạng thái cùng URL cuối, còn Kiểm tra HTTP Header hiển thị header thô của từng bước trong mục Redirects.
Chuyển hướng 302 và SEO
Google coi hai loại chuyển hướng là hai chỉ dẫn khác nhau. Với chuyển hướng tạm thời (302, 303, 307), Googlebot có theo, nhưng Google không xem đó là dấu hiệu rằng URL đích nên là URL chuẩn (canonical), nên trang nguồn thường vẫn ở trong kết quả tìm kiếm. URL đích vẫn có thể được lập chỉ mục nếu các tín hiệu khác trỏ tới nó (Google Search Central).
Chuyển hướng vĩnh viễn (301, 308) nói điều ngược lại: hãy hiển thị URL mới. Vì vậy câu hỏi thật sự không phải "302 có truyền PageRank không?" mà là "tôi muốn URL nào xuất hiện trong kết quả tìm kiếm?". Thẻ rel=canonical của bạn là một trong các tín hiệu khác; Kiểm Tra Thẻ Meta cho thấy một trang khai báo URL nào.
- Dùng 301 hoặc 308 cho việc dời vĩnh viễn — tên miền mới, cấu trúc URL mới, gộp trang
- Dùng 302 cho việc tạm thời — đăng nhập, A/B test, chiến dịch
- Đừng để việc dời vĩnh viễn ở 302 — Google có thể tiếp tục hiển thị URL cũ
- Giữ chuỗi ngắn — mỗi bước tốn một vòng đi-về, và Googlebot mặc định theo tối đa 10 bước (Google)
Vì sao 302 biến yêu cầu POST thành GET
Đây là điều đáng ngạc nhiên nhất ở 302. Các đặc tả đầu tiên không bao giờ cho phép client đổi phương thức, nhưng trình duyệt vẫn đổi POST thành GET khi gặp 302. Ngày nay Fetch Standard mà trình duyệt triển khai đã viết thói quen đó thành quy định: với 301 hoặc 302, POST thành GET và phần thân bị bỏ (Fetch Standard).
Vì vậy khi trình duyệt gửi POST /submit-form và máy chủ trả 302 Found, trình duyệt tiếp tục bằng GET /thank-you, và dữ liệu biểu mẫu mất đi. Trình duyệt giữ nguyên PUT và DELETE; các client khác thì khác: Python requests đổi mọi phương thức trừ HEAD thành GET khi gặp 302, còn curl -L đổi POST thành GET với 301, 302 và 303 (--post302 giữ POST với 302).
# What you send:
POST /submit-form HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
name=Alice&email=alice@example.com
# Server responds with 302:
HTTP/1.1 302 Found
Location: /thank-you
# Browser follows with GET (form data dropped!):
GET /thank-you HTTP/1.1
Host: example.comNếu bạn cần chuyển hướng giữ nguyên phương thức gốc (POST vẫn là POST, PUT vẫn là PUT), hãy dùng 307 Temporary Redirect. Nếu bạn cố ý muốn bỏ phần thân và chuyển sang GET, tức mẫu POST/Redirect/GET kinh điển, hãy dùng 303 See Other. Cả hai đều rõ ràng; 302 thì không.
Các lỗi 302 thường gặp và cách sửa
Khi một 302 gặp sự cố, thường là một trong các trường hợp sau:
- 302 thay vì 200 — một màn hình đăng nhập, một client không theo chuyển hướng, hoặc một biến thể URL (xem "Vì sao tôi nhận 302" ở trên)
- 302 không có header Location — không gì có thể theo nó, và trình duyệt hiển thị phần thân của chính 302, thường là trống. Hãy đặt
Locationtrước khi gửi trạng thái - 302 trỏ về chính nó — vòng lặp chuyển hướng: quy tắc kích hoạt ngay trên đích của nó. Hãy thêm điều kiện còn thiếu
- Biểu mẫu mất dữ liệu — POST → 302 → GET làm mất phần thân. Dùng 303 để cố ý hiển thị trang kết quả, hoặc 307 để giữ POST
- 302 bị kẹt — máy chủ gửi kèm
Cache-Control: max-agehoặcExpires, nên trình duyệt đã cache nó, hoặc CDN của bạn đã cache (với nội dung Cloudflare cache, nó giữ 302 trong 20 phút trừ khi header nói khác, tài liệu Cloudflare). Hãy gỡ các header đó, xóa cache CDN và xóa cache trình duyệt - 302 trên môi trường thật nhưng không có ở máy cục bộ — thường là quy tắc của CDN, bộ cân bằng tải hoặc proxy thêm chuyển hướng. Hãy kiểm tra trực tiếp máy chủ gốc để biết
Vòng lặp chuyển hướng 302: cách chẩn đoán
Vòng lặp chuyển hướng là khi URL A đưa bạn tới B và B đưa bạn quay lại A. Sau 20 lần chuyển hướng, giới hạn trong Fetch Standard, Chrome bỏ cuộc với ERR_TOO_MANY_REDIRECTS còn Firefox báo "Trang này không chuyển hướng đúng cách".
Một nguyên nhân kinh điển là chế độ mã hóa Flexible của Cloudflare: Cloudflare kết nối tới máy chủ của bạn bằng HTTP thường, máy chủ chuyển HTTP sang HTTPS, và Cloudflare lại hỏi bằng HTTP (tài liệu Cloudflare).
# Trace the full redirect chain (limit to 10 hops to avoid infinite loops)
curl -ILs --max-redirs 10 https://example.com 2>&1 | grep -i 'HTTP/\|location:'
# Example of a loop:
# HTTP/2 302
# location: http://example.com/
# HTTP/1.1 302 Found
# Location: https://example.com/
# HTTP/2 302
# location: http://example.com/ <-- loop confirmedNếu cùng một URL cứ quay lại trong Location, dù tự trỏ về chính nó hay hai URL thay phiên nhau, thì bạn có một vòng lặp (với chế độ Flexible của Cloudflare, https://example.com/ chuyển hướng về chính nó). Để xem cách khắc phục đầy đủ, hãy đọc hướng dẫn ERR_TOO_MANY_REDIRECTS của chúng tôi. Kiểm tra Redirect của DNS Robot theo chuỗi từ máy chủ của chúng tôi và dừng ở chỗ nó lặp.
Thực hành tốt nhất với mã trạng thái 302
Vài thói quen giúp tránh phần lớn sự cố với 302:
- Luôn gửi header Location — thiếu nó thì không gì theo được chuyển hướng
- Đừng thêm header cache — 302 không có
max-agehoặcExpiresthì không được cache, đúng như bạn muốn - Chú ý URL tuyệt đối phía sau proxy — trong mã ứng dụng,
/logintương đối tránh làm lộ tên máy chủ nội bộ hoặchttp://vào Location; nginx và Apache tạo URL tuyệt đối từ cài đặt của chính chúng - Giữ ở một bước —
A → Bthì ổn;A → B → Cthêm một vòng đi-về cho mỗi khách truy cập - Đừng bao giờ dùng 302 cho POST tới trang khác — dùng 303 để hiển thị trang kết quả, hoặc 307 để giữ POST
- Rà soát các chuyển hướng tạm thời cũ — chúng thường tồn tại lâu hơn lý do của mình. Hãy kiểm tra bằng Kiểm tra Redirect
- Đổi sang 301 ngay khi việc dời trở thành vĩnh viễn
Trình duyệt và công cụ xử lý 302 như thế nào
Các client thống nhất việc theo 302 nhưng khác nhau về giới hạn và về chuyện xảy ra với phương thức:
| Client | Làm gì với 302 | Giới hạn chuyển hướng |
|---|---|---|
| Chrome, Edge, Firefox, Safari | Theo ngay; POST thành GET | 20 (Fetch Standard) |
| fetch() trong JavaScript | Theo mặc định (redirect: "follow"); cùng quy tắc với POST | 20 |
| curl | Không theo; chỉ in phần thân của 302, thường là trống (thêm -i hoặc -I để xem trạng thái và Location) | Không có (không theo) |
| curl -L | Theo; POST thành GET với 301, 302 và 303 (--post301, --post302, --post303 giữ nguyên nó) | 50 (--max-redirs) |
| wget | Theo | 20 (--max-redirect) |
| Python requests | Theo; mọi phương thức trừ HEAD thành GET | 30 |
| Googlebot | Theo; giữ URL nguồn làm kết quả tìm kiếm | Mặc định 10 bước |
Để xem cách diễn đạt chính xác, hãy đọc định nghĩa 302 trong RFC 9110 và trang 302 của MDN.
Theo dõi chuỗi chuyển hướng trong vài giây
Kiểm tra Redirect miễn phí của DNS Robot cho bạn xem mọi bước trong chuỗi: mã trạng thái, header Location và đích cuối từ một máy chủ trung lập (không có cache trình duyệt).
Nguồn
- RFC 9110: HTTP Semantics, 302 Found, IETF
- Fetch Standard: HTTP-redirect fetch, WHATWG
- Redirects and Google Search, Google Search Central
- Configure cache by status code (default 20 minutes for 302), Cloudflare
Câu Hỏi Thường Gặp
Mã trạng thái 302 nghĩa là gì?
Vì sao tôi nhận 302 thay vì 200?
"Lỗi 302": có thật sự là lỗi không?
302 có tốt hơn 301 không?
Chuyển hướng 302 có hại cho SEO không?
Khác biệt giữa 302 và 307 là gì?
Tại sao POST của tôi thành GET sau 302?
Chuyển hướng 302 có bị trình duyệt cache không?
Làm sao để gửi chuyển hướng 302?
Làm sao kiểm tra một URL có trả 302 không?
Bài viết liên quan
Công cụ liên quan
Kiểm tra Redirect
Kiểm tra chuyển hướng URL, chuỗi chuyển hướng và mã trạng thái HTTP cho SEO
Kiểm tra HTTP Header
Phân tích header phản hồi HTTP và chấm điểm header bảo mật
Kiểm Tra Chứng Chỉ SSL
Xác minh tính hợp lệ chứng chỉ SSL và chi tiết bảo mật
Tra Cứu DNS
Mọi bản ghi DNS từ máy chủ của chính tên miền, cạnh bộ nhớ đệm của Google và Cloudflare



