Files
James Anderson bc586788a2 fix(middleware): preserve query params on rewrite (#1375)
* fix(middleware): preserve query params on rewrite

When middleware (or a `next.config.js` rewrite) sends a request to a new
target, vinext was throwing away the original request's query string,
breaking `getServerSideProps`/route-handler `query` for any URL of the
form `/rewrite-me?key=value`.

Match Next.js's behaviour:
`Object.assign(parsedUrl.query, rewrittenParsedUrl.query)` — keep the
original query first, let the rewrite-target's query win on key
conflicts. Applied to:

- middleware rewrites (middleware-runtime.ts)
- beforeFiles / afterFiles / fallback config rewrites (prod-server.ts,
  index.ts, deploy.ts)

Closes #1342

References:
- https://github.com/vercel/next.js/blob/canary/packages/next/src/server/route-modules/route-module.ts (Object.assign merge)
- https://github.com/vercel/next.js/blob/canary/test/e2e/edge-pages-support/index.test.ts (rewrite query expectations)

* test(query): document URL-encoded space normalization on rewrite merge

Addresses Bonk review observations on #1375:
- Add test confirming `%20` → `+` normalization through URLSearchParams
  is intentional and lossless (downstream consumers re-parse).
- Drop unreachable `?? ""` fallback in mergeRewriteQuery; `String#split`
  always yields a string.
2026-05-21 11:38:52 +01:00

36 lines
789 B
TypeScript

import { useRouter } from "next/router";
interface PostProps {
id: string;
query: Record<string, string | string[] | undefined>;
}
export default function Post({ id, query }: PostProps) {
const router = useRouter();
return (
<div>
<h1 data-testid="post-title">Post: {id}</h1>
<p data-testid="pathname">Pathname: {router.pathname}</p>
<p data-testid="as-path">As Path: {router.asPath}</p>
<p data-testid="query">Query ID: {router.query.id}</p>
<p data-testid="gssp-query">{JSON.stringify(query)}</p>
</div>
);
}
export async function getServerSideProps({
params,
query,
}: {
params: { id: string };
query: Record<string, string | string[] | undefined>;
}) {
return {
props: {
id: params.id,
query,
},
};
}