Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove deprecation for relative URL usage in middlewares #34461

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions errors/middleware-relative-urls.md
Expand Up @@ -2,11 +2,11 @@

#### Why This Error Occurred

You are using a Middleware function that uses `Response.redirect(url)`, `NextResponse.redirect(url)` or `NextResponse.rewrite(url)` where `url` is a relative or an invalid URL. Currently this will work, but building a request with `new Request(url)` or running `fetch(url)` when `url` is a relative URL will **not** work. For this reason and to bring consistency to Next.js Middleware, this behavior will be deprecated soon in favor of always using absolute URLs.
You are using a Middleware function that uses `Response.redirect(url)`, `NextResponse.redirect(url)` or `NextResponse.rewrite(url)` where `url` is a relative or an invalid URL. Prior to Next.js 12.1, we allowed passing relative URLs. However, constructing a request with `new Request(url)` or running `fetch(url)` when `url` is a relative URL **does not** work. For this reason and to bring consistency to Next.js Middleware, this behavior has been deprecated and now removed.

#### Possible Ways to Fix It

To fix this warning you must always pass absolute URL for redirecting and rewriting. There are several ways to get the absolute URL but the recommended way is to clone `NextURL` and mutate it:
To fix this error you must always pass absolute URL for redirecting and rewriting. There are several ways to get the absolute URL but the recommended way is to clone `NextURL` and mutate it:

```typescript
import type { NextRequest } from 'next/server'
Expand Down
12 changes: 5 additions & 7 deletions packages/next/server/web/utils.ts
Expand Up @@ -149,18 +149,16 @@ export function splitCookiesString(cookiesString: string) {
}

/**
* We will be soon deprecating the usage of relative URLs in Middleware introducing
* URL validation. This helper puts the future code in place and prints a warning
* for cases where it will break. Meanwhile we preserve the previous behavior.
* Validate the correctness of a user-provided URL.
*/
export function validateURL(url: string | URL): string {
try {
return String(new URL(String(url)))
} catch (error: any) {
console.log(
`warn -`,
'using relative URLs for Middleware will be deprecated soon - https://nextjs.org/docs/messages/middleware-relative-urls'
throw new Error(
`URLs is malformed. Please use only absolute URLs - https://nextjs.org/docs/messages/middleware-relative-urls`,
// @ts-expect-error This will work for people who enable the error causes polyfill
{ cause: error }
)
return String(url)
}
}
Expand Up @@ -12,7 +12,7 @@ export async function middleware(request) {
) {
const isExternal = url.searchParams.get('override') === 'external'
return NextResponse.rewrite(
isExternal ? 'https://vercel.com' : '/rewrites/a'
isExternal ? 'https://vercel.com' : new URL('/rewrites/a', request.url)
)
}

Expand Down
39 changes: 30 additions & 9 deletions test/integration/middleware/core/test/index.test.js
Expand Up @@ -19,7 +19,7 @@ const context = {}
context.appDir = join(__dirname, '../')

const middlewareWarning = 'using beta Middleware (not covered by semver)'
const urlsWarning = 'using relative URLs for Middleware will be deprecated soon'
const urlsError = 'Please use only absolute URLs'

describe('Middleware base tests', () => {
describe('dev mode', () => {
Expand Down Expand Up @@ -110,7 +110,7 @@ describe('Middleware base tests', () => {
})
})

function urlTests(log, locale = '') {
function urlTests(_log, locale = '') {
it('rewrites by default to a target location', async () => {
const res = await fetchViaHTTP(context.appPort, `${locale}/urls`)
const html = await res.text()
Expand Down Expand Up @@ -146,18 +146,39 @@ function urlTests(log, locale = '') {
})

it('warns when using Response.redirect with a relative URL', async () => {
await fetchViaHTTP(context.appPort, `${locale}/urls/relative-redirect`)
expect(log.output).toContain(urlsWarning)
const response = await fetchViaHTTP(
context.appPort,
`${locale}/urls/relative-redirect`
)
expect(await response.json()).toEqual({
error: {
message: expect.stringContaining(urlsError),
},
})
})

it('warns when using NextResponse.redirect with a relative URL', async () => {
await fetchViaHTTP(context.appPort, `${locale}/urls/relative-next-redirect`)
expect(log.output).toContain(urlsWarning)
const response = await fetchViaHTTP(
context.appPort,
`${locale}/urls/relative-next-redirect`
)
expect(await response.json()).toEqual({
error: {
message: expect.stringContaining(urlsError),
},
})
})

it('warns when using NextResponse.rewrite with a relative URL', async () => {
await fetchViaHTTP(context.appPort, `${locale}/urls/relative-next-rewrite`)
expect(log.output).toContain(urlsWarning)
it('throws when using NextResponse.rewrite with a relative URL', async () => {
const response = await fetchViaHTTP(
context.appPort,
`${locale}/urls/relative-next-rewrite`
)
expect(await response.json()).toEqual({
error: {
message: expect.stringContaining(urlsError),
},
})
})
}

Expand Down