Rewrites
Sometimes you want to redirect a user from the current page to another page, but you want to keep the current URL in the browser history.
Let's say a user tries to access an article which is indexed by its name,
e.g /articles/qwik-is-very-quick.
but in our code, we access it by its id, on our directory structure.
src/routes/articles/
├── [id]
├─── index.tsx
import type { RequestHandler } from '@qwik.dev/router';
export const onRequest: RequestHandler = async ({ url, rewrite, internalRequest }) => {
if (internalRequest) {
return;
}
const pattern = /^\/articles\/(.*)$/;
// Detects /articles/<article-name>, returns null if url does not match the pattern.
const match = url.pathname.match(pattern);
if (match) {
const articleName = match[1];
const { id } = await db.getArticleByName(articleName);
throw rewrite(`/articles/${id}`);
}
};
Check internalRequest before applying broad rewrite rules. Qwik Router uses internal JSON
requests for route loader fetches and fetch-based action submissions, and those requests must keep
their internal routing behavior.
Rewrites and client navigation
A rewrite() happens on the server, so on a client navigation the router can't know which route a rewritten URL renders. When the URL has no page of its own, only matches a dynamic ([param]) or wildcard route, or matches a route without a component, the router asks the server where the URL finally routes to (q-route.json), then renders that route while keeping the original URL.
A static route that matches the URL exactly is always rendered as-is, so don't keep a page on a URL that your middleware rewrites.
The answer is sent with the response headers your middleware has set when it calls rewrite(), and private if it set no Cache-Control, like loaders. To cache it (browser, CDN, ...), set the headers before rewriting. If the rewrite depends on the user (cookies, auth), keep it private or Vary accordingly:
export const onRequest: RequestHandler = async ({ url, rewrite, cacheControl, headers }) => {
const match = url.pathname.match(/^\/articles\/(.*)$/);
if (match) {
const { id } = await db.getArticleByName(match[1]);
cacheControl({ maxAge: 300, staleWhileRevalidate: 3600 }, 'CDN-Cache-Control');
headers.set('Cache-Tag', `article-${id}`);
throw rewrite(`/articles/${id}`);
}
};
The rewrite() function, which was destructured in the RequestHandler function arguments, is invoked with a pathname string.
throw rewrite(`/articles/777/`);