HTTP 308 Permanent Redirect is the permanent counterpart to 307 Temporary Redirect — it indicates the resource has permanently moved to a new URL while guaranteeing the HTTP method and body are preserved through the redirect. Use 308 instead of 301 when the redirected request MUST maintain its original method (POST, PUT, DELETE). This is essential for API endpoints that move to new URLs where clients submit data via non-GET methods.
Response includes the status code, standard headers (including Content-Type), and a small diagnostic JSON body describing the request and returned status.
Simulator URL (copy in the app after load — not a normal link):
https://httpstatus.com/api/status/308
Example request:
curl -i "https://httpstatus.com/api/status/308"The URL of the requested resource has been changed permanently.
On this code, Inspector focuses on semantics, headers, and correctness warnings that commonly affect clients and caches.
308 Permanent Redirect (RFC 7538) completes the redirect matrix: 301=permanent+may change method, 308=permanent+must preserve method, 302=temporary+may change method, 307=temporary+must preserve method. Like 301, 308 is cacheable by default and signals search engines to update their index. The client MUST use the new URL for future requests. Not all older clients support 308 — test with your target audience. CDN behavior varies: some CDNs follow 308 preserving the method, others may need configuration. 308 should be accompanied by a Location header pointing to the new permanent URL.
app.get('/old-path', (req, res) => {
res.redirect(308, '/new-path');
});from fastapi.responses import RedirectResponse
@app.get('/old-path')
async def old_path():
return RedirectResponse('/new-path', status_code=308)@GetMapping("/old-path")
public ResponseEntity<Void> oldPath() {
return ResponseEntity.status(308)
.header("Location", "/new-path")
.build();
}func oldPathHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/new-path", 308)
}