Remove deprecation for relative URL usage in middlewares (#34461)

* Remove deprecation for relative URL usage in middlewares

* fix tests

Co-authored-by: JJ Kasper <jj@jjsweb.site>
This commit is contained in:
Gal Schlezinger 2022-02-17 17:12:36 +02:00 committed by GitHub
parent d4d79b2d9b
commit f0f322c0d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 19 deletions

View file

@ -2,11 +2,11 @@
#### Why This Error Occurred #### 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 #### 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 ```typescript
import type { NextRequest } from 'next/server' import type { NextRequest } from 'next/server'

View file

@ -149,18 +149,16 @@ export function splitCookiesString(cookiesString: string) {
} }
/** /**
* We will be soon deprecating the usage of relative URLs in Middleware introducing * Validate the correctness of a user-provided URL.
* 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.
*/ */
export function validateURL(url: string | URL): string { export function validateURL(url: string | URL): string {
try { try {
return String(new URL(String(url))) return String(new URL(String(url)))
} catch (error: any) { } catch (error: any) {
console.log( throw new Error(
`warn -`, `URLs is malformed. Please use only absolute URLs - https://nextjs.org/docs/messages/middleware-relative-urls`,
'using relative URLs for Middleware will be deprecated soon - 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)
} }
} }

View file

@ -12,7 +12,7 @@ export async function middleware(request) {
) { ) {
const isExternal = url.searchParams.get('override') === 'external' const isExternal = url.searchParams.get('override') === 'external'
return NextResponse.rewrite( return NextResponse.rewrite(
isExternal ? 'https://vercel.com' : '/rewrites/a' isExternal ? 'https://vercel.com' : new URL('/rewrites/a', request.url)
) )
} }

View file

@ -19,7 +19,7 @@ const context = {}
context.appDir = join(__dirname, '../') context.appDir = join(__dirname, '../')
const middlewareWarning = 'using beta Middleware (not covered by semver)' 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('Middleware base tests', () => {
describe('dev mode', () => { describe('dev mode', () => {
@ -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 () => { it('rewrites by default to a target location', async () => {
const res = await fetchViaHTTP(context.appPort, `${locale}/urls`) const res = await fetchViaHTTP(context.appPort, `${locale}/urls`)
const html = await res.text() const html = await res.text()
@ -146,18 +146,39 @@ function urlTests(log, locale = '') {
}) })
it('warns when using Response.redirect with a relative URL', async () => { it('warns when using Response.redirect with a relative URL', async () => {
await fetchViaHTTP(context.appPort, `${locale}/urls/relative-redirect`) const response = await fetchViaHTTP(
expect(log.output).toContain(urlsWarning) 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 () => { it('warns when using NextResponse.redirect with a relative URL', async () => {
await fetchViaHTTP(context.appPort, `${locale}/urls/relative-next-redirect`) const response = await fetchViaHTTP(
expect(log.output).toContain(urlsWarning) 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 () => { it('throws when using NextResponse.rewrite with a relative URL', async () => {
await fetchViaHTTP(context.appPort, `${locale}/urls/relative-next-rewrite`) const response = await fetchViaHTTP(
expect(log.output).toContain(urlsWarning) context.appPort,
`${locale}/urls/relative-next-rewrite`
)
expect(await response.json()).toEqual({
error: {
message: expect.stringContaining(urlsError),
},
})
}) })
} }