Redirects: proxy vs. 301.
Not every path needs to be proxied. Some should permanently move. A reverse proxy is also the right place to enforce HTTPS and the canonical host.
When to redirect instead of proxy
- The URL structure changed.
/old-blog/x→/blog/x. - You're deprecating a section entirely.
- You want to consolidate
example.com→www.example.com. - You want to force HTTPS.
The right status code
- 301 Moved Permanently — SEO transfers. Use for stable, permanent moves.
- 302 Found — temporary. Use sparingly.
- 308 Permanent Redirect — like 301 but preserves the HTTP method (important for non-GET requests).
Pattern: redirect rule in front of proxy rules
const RULES = [
// Force HTTPS on canonical host
{ test: (url) => url.protocol === 'http:', redirect: (url) => `https://${url.host}${url.pathname}${url.search}` },
// Consolidate apex onto www
{ test: (url) => url.hostname === 'example.com', redirect: (url) => `https://www.example.com${url.pathname}${url.search}` },
// Permanent path move
{ test: (url) => url.pathname.startsWith('/old-blog/'), redirect: (url) => `https://www.example.com/blog${url.pathname.slice(9)}${url.search}` },
// then proxy rules…
];
for (const r of RULES) {
if (r.test && r.test(url)) {
return Response.redirect(r.redirect(url), 301);
}
} Try it: mix redirects and proxy rules
Edit the config, then enter a request URL to see what the Worker would do. Nothing is sent over the network — this is a faithful reimplementation of the same rules in the browser.
Path rules (first match wins)
Gotchas
Redirect chains hurt SEO. If
example.com/old-blog/x
→ www.example.com/old-blog/x → www.example.com/blog/x,
that's two hops. Collapse them into one rule that goes straight to the final URL.
Don't proxy a redirect. If the upstream itself returns a 301 with
its origin host in the
Location, rewrite that header before passing it back:
upstream.headers.set('location', loc.replace(origin, canonical)).