Skip to content

Commit 1ed738f

Browse files
authored
Fix middleware search params (#844)
* fix middleware search params with multiple value * changeset and lint * review fix
1 parent 64ee684 commit 1ed738f

File tree

5 files changed

+64
-27
lines changed

5 files changed

+64
-27
lines changed

.changeset/khaki-dragons-build.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@opennextjs/aws": patch
3+
---
4+
5+
Fix middleware search params with multiple values
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
export default async function RewriteDestination(props: {
2-
searchParams: Promise<{ a: string }>;
2+
searchParams: Promise<{ a: string; multi?: string[] }>;
33
}) {
44
const searchParams = await props.searchParams;
55
return (
66
<div>
77
<div>Rewritten Destination</div>
88
<div>a: {searchParams.a}</div>
9+
<div>multi: {searchParams.multi?.join(", ")}</div>
910
</div>
1011
);
1112
}

examples/app-pages-router/middleware.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ export function middleware(request: NextRequest) {
2727
u.searchParams.set("a", "b");
2828
return NextResponse.rewrite(u);
2929
}
30+
if (path === "/rewrite-multi-params") {
31+
const u = new URL("/rewrite-destination", `${protocol}://${host}`);
32+
u.searchParams.append("multi", "0");
33+
u.searchParams.append("multi", "1");
34+
u.searchParams.append("multi", "2");
35+
u.searchParams.set("a", "b");
36+
return NextResponse.rewrite(u);
37+
}
3038
if (path === "/api/middleware") {
3139
return new NextResponse(JSON.stringify({ hello: "middleware" }), {
3240
status: 200,

packages/open-next/src/core/routing/middleware.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import type { InternalEvent, InternalResult } from "types/open-next.js";
1010
import { emptyReadableStream } from "utils/stream.js";
1111

12+
import { getQueryFromSearchParams } from "../../overrides/converters/utils.js";
1213
import { localizePath } from "./i18n/index.js";
1314
import {
1415
convertBodyToReadableStream,
@@ -142,7 +143,7 @@ export async function handleMiddleware(
142143
// NOTE: the header was added to `req` from above
143144
const rewriteUrl = responseHeaders.get("x-middleware-rewrite");
144145
let isExternalRewrite = false;
145-
let middlewareQueryString = internalEvent.query;
146+
let middlewareQuery = internalEvent.query;
146147
let newUrl = internalEvent.url;
147148
if (rewriteUrl) {
148149
newUrl = rewriteUrl;
@@ -151,17 +152,14 @@ export async function handleMiddleware(
151152
isExternalRewrite = true;
152153
} else {
153154
const rewriteUrlObject = new URL(rewriteUrl);
155+
// Search params from the rewritten URL override the original search params
154156

155-
// Reset the query params if the middleware is a rewrite
156-
middlewareQueryString = middlewareQueryString.__nextDataReq
157-
? {
158-
__nextDataReq: middlewareQueryString.__nextDataReq,
159-
}
160-
: {};
157+
middlewareQuery = getQueryFromSearchParams(rewriteUrlObject.searchParams);
161158

162-
rewriteUrlObject.searchParams.forEach((v: string, k: string) => {
163-
middlewareQueryString[k] = v;
164-
});
159+
// We still need to add internal search params to the query string for pages router on older versions of Next.js
160+
if ("__nextDataReq" in internalEvent.query) {
161+
middlewareQuery.__nextDataReq = internalEvent.query.__nextDataReq;
162+
}
165163
}
166164
}
167165

@@ -188,7 +186,7 @@ export async function handleMiddleware(
188186
headers: { ...internalEvent.headers, ...reqHeaders },
189187
body: internalEvent.body,
190188
method: internalEvent.method,
191-
query: middlewareQueryString,
189+
query: middlewareQuery,
192190
cookies: internalEvent.cookies,
193191
remoteAddress: internalEvent.remoteAddress,
194192
isExternalRewrite,
Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,44 @@
11
import { expect, test } from "@playwright/test";
22

3-
test("Middleware Rewrite", async ({ page }) => {
4-
await page.goto("/");
5-
await page.locator('[href="/rewrite"]').click();
3+
test.describe("Middleware Rewrite", () => {
4+
test("Simple Middleware Rewrite", async ({ page }) => {
5+
await page.goto("/");
6+
await page.locator('[href="/rewrite"]').click();
67

7-
await page.waitForURL("/rewrite");
8-
let el = page.getByText("Rewritten Destination", { exact: true });
9-
await expect(el).toBeVisible();
10-
el = page.getByText("a: b", { exact: true });
11-
await expect(el).toBeVisible();
12-
// Loading page should also rewrite
13-
await page.goto("/rewrite");
14-
await page.waitForURL("/rewrite");
15-
el = page.getByText("Rewritten Destination", { exact: true });
16-
await expect(el).toBeVisible();
17-
el = page.getByText("a: b", { exact: true });
18-
await expect(el).toBeVisible();
8+
await page.waitForURL("/rewrite");
9+
let el = page.getByText("Rewritten Destination", { exact: true });
10+
await expect(el).toBeVisible();
11+
el = page.getByText("a: b", { exact: true });
12+
await expect(el).toBeVisible();
13+
// Loading page should also rewrite
14+
await page.goto("/rewrite");
15+
await page.waitForURL("/rewrite");
16+
el = page.getByText("Rewritten Destination", { exact: true });
17+
await expect(el).toBeVisible();
18+
el = page.getByText("a: b", { exact: true });
19+
await expect(el).toBeVisible();
20+
});
21+
22+
test("Middleware Rewrite with multiple search params", async ({ page }) => {
23+
await page.goto("/rewrite-multi-params");
24+
let el = page.getByText("Rewritten Destination", { exact: true });
25+
await expect(el).toBeVisible();
26+
el = page.getByText("a: b", { exact: true });
27+
await expect(el).toBeVisible();
28+
el = page.getByText("multi: 0, 1, 2", { exact: true });
29+
await expect(el).toBeVisible();
30+
});
31+
32+
test("Middleware Rewrite should override original search params", async ({
33+
page,
34+
}) => {
35+
await page.goto("/rewrite?a=1&multi=3");
36+
let el = page.getByText("Rewritten Destination", { exact: true });
37+
await expect(el).toBeVisible();
38+
el = page.getByText("a: b", { exact: true });
39+
await expect(el).toBeVisible();
40+
el = page.getByText("multi:", { exact: true });
41+
await expect(el).toBeVisible();
42+
expect(el).toHaveText("multi:");
43+
});
1944
});

0 commit comments

Comments
 (0)