Skip to content

Commit

Permalink
[edge] fix URLSearchParams lacking data from rewrite
Browse files Browse the repository at this point in the history
Given the change in vercel#40076, when a middleware rewrites into an Edge
API route and changes the querystring, the changed querystring does
not appear in the incoming NextRequest object in the Edge API route

```ts
// middleware.ts
export function middleware(req: NextRequest) {
  const url = req.nextUrl
    url.pathname = "/api/hello"
    url.searchParams.set("foo", "bar")
    return NextResponse.rewrite(url)
}

// pages/api/hello.ts
import { NextRequest } from "next/server"

export default function handler(req: NextRequest) {
  return NextResponse.json(req.nextUrl.searchParams.get("foo"))
}

export const config = { runtime: "experimental-edge" }
```

Our expectation when requesting `/api/hello` is to see `"bar"`,
but instead we are getting `null` back.

This commit fixes this issue by reading the given `query` instead of using
the initial querystring provided with the user request (prior to rewriting)
  • Loading branch information
Schniz committed Sep 8, 2022
1 parent a4d907a commit 37e3323
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 3 deletions.
4 changes: 1 addition & 3 deletions packages/next/server/next-server.ts
Expand Up @@ -2049,9 +2049,7 @@ export default class NextNodeServer extends BaseServer {

// For middleware to "fetch" we must always provide an absolute URL
const isDataReq = !!params.query.__nextDataReq
const query = urlQueryToSearchParams(
Object.assign({}, getRequestMeta(params.req, '__NEXT_INIT_QUERY') || {})
).toString()
const query = urlQueryToSearchParams(params.query).toString()
const locale = params.query.__nextLocale
// Use original pathname (without `/page`) instead of appPath for url
let normalizedPathname = params.page
Expand Down
6 changes: 6 additions & 0 deletions test/e2e/middleware-general/app/middleware.js
Expand Up @@ -47,6 +47,12 @@ export async function middleware(request) {
return NextResponse.next()
}

if (url.pathname === '/api/edge-search-params') {
const newUrl = url.clone()
newUrl.searchParams.set('foo', 'bar')
return NextResponse.rewrite(newUrl)
}

if (url.pathname === '/') {
url.pathname = '/ssg/first'
return NextResponse.rewrite(url)
Expand Down
10 changes: 10 additions & 0 deletions test/e2e/middleware-general/app/pages/api/edge-search-params.js
@@ -0,0 +1,10 @@
import { NextResponse } from 'next/server'

export const config = { runtime: 'experimental-edge' }

/**
* @param {import('next/server').NextRequest}
*/
export default (req) => {
return NextResponse.json(Object.fromEntries(req.nextUrl.searchParams))
}
11 changes: 11 additions & 0 deletions test/e2e/middleware-general/test/index.test.ts
Expand Up @@ -157,6 +157,17 @@ describe('Middleware Runtime', () => {
})
}

it('passes search params with rewrites', async () => {
const response = await fetchViaHTTP(next.url, `/api/edge-search-params`, {
a: 'b',
})
await expect(response.json()).resolves.toMatchObject({
a: 'b',
// included from middleware
foo: 'bar',
})
})

it('should have init header for NextResponse.redirect', async () => {
const res = await fetchViaHTTP(
next.url,
Expand Down

0 comments on commit 37e3323

Please sign in to comment.