HTTP
303 - See Other
Getting a 303 See Other means the server wants you to fetch the result of your POST/PUT/DELETE operation using GET at a different URL—the Location header shows where to get the result, and you must use GET even if the original request was POST. This client-side redirect (3xx) is designed for POST-after-GET patterns. Most common after form submissions when results are available elsewhere, but also appears when POST operations redirect to result pages, form submissions redirect to confirmation pages, or operations redirect to status pages.
#Common Causes
- →Frontend: POST request submitted. Form submission completed. Operation result available elsewhere. Need to fetch result with GET.
- →Backend: POST operation completed. Form submission processed. Result available at different URL. Server redirects to result page.
- →Infrastructure: Form handler redirects after submission. Operation result served at different endpoint.
✓Solutions
- 1Step 1: Diagnose - Check DevTools Network tab Location header—303 responses show where to GET the result. Review redirect after POST. Check if GET is required.
- 2Step 2: Diagnose - Server logs show POST operation completion. Review redirect configuration. Check result URL. Verify GET requirement.
- 3Step 3: Fix - Client-side: Follow Location header with GET request (not POST). Fetch result page with GET. Handle redirect after form submission.
- 4Step 4: Fix - Server-side: Return 303 with Location header after POST. Ensure result is available at Location URL. Use GET for result page.
- 5Step 5: Fix - Infrastructure: Configure form handler redirects. Set up result pages. Ensure GET works at redirect URL.
</>Code Examples
Fetch API: Handle 303 See Other Redirects
1// Client-side: Handle 303 - must use GET for redirect
2async function submitForm(formData) {
3 const response = await fetch('/api/submit', {
4 method: 'POST',
5 headers: {
6 'Content-Type': 'application/json',
7 },
8 body: JSON.stringify(formData),
9 redirect: 'manual', // Handle redirect manually
10 });
11
12 if (response.status === 303) {
13 const location = response.headers.get('Location');
14 console.log('See Other - redirect to:', location);
15
16 // 303 requires GET request to new location (not POST)
17 const resultResponse = await fetch(location, {
18 method: 'GET', // Must use GET
19 });
20
21 return resultResponse.json();
22 }
23
24 return response.json();
25}
26
27// Form submission with 303 handling
28async function handleFormSubmission(form) {
29 const formData = new FormData(form);
30
31 const response = await fetch('/api/form-submit', {
32 method: 'POST',
33 body: formData,
34 redirect: 'manual',
35 });
36
37 if (response.status === 303) {
38 // Redirect to result/confirmation page
39 const resultUrl = response.headers.get('Location');
40 window.location.href = resultUrl; // Browser will GET the page
41 return;
42 }
43
44 // Handle other status codes
45 const result = await response.json();
46 displayResult(result);
47}
48
49// POST-after-GET pattern
50async function createResource(data) {
51 const response = await fetch('/api/resources', {
52 method: 'POST',
53 headers: { 'Content-Type': 'application/json' },
54 body: JSON.stringify(data),
55 redirect: 'manual',
56 });
57
58 if (response.status === 303) {
59 // GET the created resource
60 const resourceUrl = response.headers.get('Location');
61 return fetch(resourceUrl, { method: 'GET' });
62 }
63
64 return response.json();
65}Express.js: Return 303 After POST
1// Server-side: Return 303 after POST operations
2const express = require('express');
3const app = express();
4
5app.use(express.json());
6app.use(express.urlencoded({ extended: true }));
7
8// Form submission - redirect to result page
9app.post('/api/form-submit', async (req, res) => {
10 // Process form submission
11 const result = await processFormSubmission(req.body);
12
13 // Redirect to result page with GET
14 res.redirect(303, `/api/results/${result.id}`);
15});
16
17// POST operation - redirect to resource
18app.post('/api/resources', async (req, res) => {
19 // Create resource
20 const resource = await db.resources.create(req.body);
21
22 // Redirect to GET the created resource
23 res.status(303)
24 .set('Location', `/api/resources/${resource.id}`)
25 .end();
26});
27
28// File upload - redirect to status page
29app.post('/api/upload', upload.single('file'), async (req, res) => {
30 const fileId = await processUpload(req.file);
31
32 // Redirect to status/result page
33 res.redirect(303, `/api/uploads/${fileId}/status`);
34});
35
36// Operation completion - redirect to confirmation
37app.post('/api/operations', async (req, res) => {
38 const operation = await performOperation(req.body);
39
40 // Redirect to confirmation page
41 res.redirect(303, `/api/operations/${operation.id}/confirmation`);
42});
43
44// POST-after-GET pattern
45app.post('/api/orders', async (req, res) => {
46 const order = await createOrder(req.body);
47
48 // Redirect to GET the order
49 res.status(303)
50 .set('Location', `/api/orders/${order.id}`)
51 .end();
52});Nginx: Handle 303 Redirects
1# Nginx: Pass 303 redirects from backend
2server {
3 listen 80;
4 server_name api.example.com;
5
6 location /api/submit {
7 proxy_pass http://backend;
8 proxy_set_header Host $host;
9 proxy_set_header X-Real-IP $remote_addr;
10
11 # Backend returns 303, Nginx passes it through
12 proxy_redirect off;
13 }
14
15 # Or configure 303 redirect at Nginx level
16 location /api/form-submit {
17 # After POST, redirect to result page
18 if ($request_method = POST) {
19 return 303 /api/results$is_args$args;
20 }
21
22 proxy_pass http://backend;
23 }
24}↗Related Errors
Provider Information
This error code is specific to HTTP services. For more information, refer to the official HTTP documentation.