-
Notifications
You must be signed in to change notification settings - Fork 27.2k
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
feat(middleware)!: forbids middleware response body #36835
feat(middleware)!: forbids middleware response body #36835
Conversation
Failing test suitesCommit: d3931cd
Expand output● Switchable runtime (prod) › should contain _app.server in flight response (edge)
● Switchable runtime (prod) › should build /edge as a dynamic page with the edge runtime
● Switchable runtime (prod) › should build /edge-rsc as a dynamic page with the edge runtime
● Switchable runtime (dev) › should contain _app.server in flight response (edge)
Read more about building and testing Next.js in contributing.md. |
Stats from current PRDefault Build (Decrease detected ✓)General Overall increase
|
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
buildDuration | 19.9s | 20.4s | |
buildDurationCached | 7.9s | 8s | |
nodeModulesSize | 479 MB | 479 MB |
Page Load Tests Overall decrease ⚠️
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 5.268 | 5.37 | |
/ avg req/sec | 474.59 | 465.54 | |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 2.053 | 2.043 | -0.01 |
/error-in-render avg req/sec | 1217.94 | 1223.64 | +5.7 |
Client Bundles (main, webpack)
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
925.HASH.js gzip | 179 B | 179 B | ✓ |
framework-HASH.js gzip | 42 kB | 42 kB | ✓ |
main-HASH.js gzip | 29 kB | 29 kB | ✓ |
webpack-HASH.js gzip | 1.44 kB | 1.44 kB | ✓ |
Overall change | 72.6 kB | 72.6 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
_app-HASH.js gzip | 1.36 kB | 1.36 kB | ✓ |
_error-HASH.js gzip | 193 B | 193 B | ✓ |
amp-HASH.js gzip | 308 B | 308 B | ✓ |
css-HASH.js gzip | 327 B | 327 B | ✓ |
dynamic-HASH.js gzip | 2.71 kB | 2.71 kB | ✓ |
head-HASH.js gzip | 359 B | 359 B | ✓ |
hooks-HASH.js gzip | 920 B | 920 B | ✓ |
image-HASH.js gzip | 5.73 kB | 5.73 kB | ✓ |
index-HASH.js gzip | 263 B | 263 B | ✓ |
link-HASH.js gzip | 2.65 kB | 2.65 kB | ✓ |
routerDirect..HASH.js gzip | 320 B | 320 B | ✓ |
script-HASH.js gzip | 391 B | 391 B | ✓ |
withRouter-HASH.js gzip | 318 B | 318 B | ✓ |
85e02e95b279..7e3.css gzip | 107 B | 107 B | ✓ |
Overall change | 16 kB | 16 kB | ✓ |
Client Build Manifests
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
_buildManifest.js gzip | 458 B | 458 B | ✓ |
Overall change | 458 B | 458 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
index.html gzip | 532 B | 532 B | ✓ |
link.html gzip | 546 B | 546 B | ✓ |
withRouter.html gzip | 527 B | 527 B | ✓ |
Overall change | 1.6 kB | 1.6 kB | ✓ |
Default Build with SWC (Increase detected ⚠️ )
General Overall increase ⚠️
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
buildDuration | 23.2s | 23s | -222ms |
buildDurationCached | 7.8s | 8s | |
nodeModulesSize | 479 MB | 479 MB |
Page Load Tests Overall increase ✓
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 5.317 | 5.411 | |
/ avg req/sec | 470.18 | 462.02 | |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 2.148 | 2.011 | -0.14 |
/error-in-render avg req/sec | 1163.82 | 1243.01 | +79.19 |
Client Bundles (main, webpack)
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
925.HASH.js gzip | 178 B | 178 B | ✓ |
framework-HASH.js gzip | 42.7 kB | 42.7 kB | ✓ |
main-HASH.js gzip | 29.5 kB | 29.5 kB | ✓ |
webpack-HASH.js gzip | 1.45 kB | 1.45 kB | ✓ |
Overall change | 73.8 kB | 73.8 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
_app-HASH.js gzip | 1.35 kB | 1.35 kB | ✓ |
_error-HASH.js gzip | 179 B | 179 B | ✓ |
amp-HASH.js gzip | 311 B | 311 B | ✓ |
css-HASH.js gzip | 324 B | 324 B | ✓ |
dynamic-HASH.js gzip | 2.89 kB | 2.89 kB | ✓ |
head-HASH.js gzip | 357 B | 357 B | ✓ |
hooks-HASH.js gzip | 920 B | 920 B | ✓ |
image-HASH.js gzip | 5.82 kB | 5.82 kB | ✓ |
index-HASH.js gzip | 261 B | 261 B | ✓ |
link-HASH.js gzip | 2.78 kB | 2.78 kB | ✓ |
routerDirect..HASH.js gzip | 322 B | 322 B | ✓ |
script-HASH.js gzip | 392 B | 392 B | ✓ |
withRouter-HASH.js gzip | 317 B | 317 B | ✓ |
85e02e95b279..7e3.css gzip | 107 B | 107 B | ✓ |
Overall change | 16.3 kB | 16.3 kB | ✓ |
Client Build Manifests
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
_buildManifest.js gzip | 457 B | 457 B | ✓ |
Overall change | 457 B | 457 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | feugy/next.js feat/forbid-middleware-response-body | Change | |
---|---|---|---|
index.html gzip | 532 B | 532 B | ✓ |
link.html gzip | 546 B | 546 B | ✓ |
withRouter.html gzip | 528 B | 528 B | ✓ |
Overall change | 1.61 kB | 1.61 kB | ✓ |
Leverages Webpack builtin errors for better reporting
d3931cd
to
7881769
Compare
a6dad02
to
265d02e
Compare
Hi, Under this change, would it be possible to return 404's (or any other status code for that matter) still? return new Response(null, { status: 400 }) I think it should? Or would that perhaps be limited as well? |
Hi @icyJoseph. It still possible to return a 404 status, like in your example. For this reason, the best is to use export default async function middleware(request) {
return NextResponse.rewrite(new URL('/not-found', request.url))
} |
Awesome! Yeah, but if this was for API routes for instance, then, sometimes, I would just want to return plain 404, with no HTML. Good to know both pathways though. Thanks! |
One last thing, today, if I do: export function middleware(req: NextRequest) {
const response = NextResponse.next();
response.headers.set("x-foo", "bar");
return response;
} I can then collect the export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
console.log(ctx.res.getHeader("x-foo")); // logs "bar"
return { props: {} };
}; Or perhaps folks shouldn't rely on it? Thanks a bunch for your time! |
What is the reason of this change? i was planning to use middleware to replace the |
Hello @remorses! As for your use case, if I understand correctly, it's still fully possible. You can (as for now) redirect and adjust response headers: import { NextResponse } from 'next/server'
export default function() {
const response = NextResponse.redirect(whateverUrlYouNeed)
response.headers.append(yourHeader, yourHeaderValue)
return response
} There's an example for setting cookies while redirecting in the docs |
Hi @larsqa. Without entering too much into details, it's simpler and safer to limit what they can do. It mostly mitigates Next.js internal router complexity, which ultimately is securing your applications. Next.js offers other ways to return responses with API, which can now also executes on the edge (an experimental feature at the time of writing) |
Hello Next.js team! First PR here, I hope I've followed the right practices.
What's in there?
It has been decided to only support the following uses cases in Next.js' middleware:
x-middleware-rewrite
response header)Location
response header)x-middleware-next
response header)Response
orNextResponse
).All returned/thrown errors contain a link to the documentation.
This is a breaking feature compared to the beta middleware implementation, and also removes
NextResponse.json()
which makes no sense any more.How to try it?
HEADLESS=true yarn jest test/integration/middleware/core
yarn jest test/integration/middleware/build-errors
HEADLESS=true yarn jest test/development/middleware-warnings
Notes to reviewers
The limitation happens in next's web adapter.
The initial implementation was to checkresponse.body
existence, but it turns outResponse.redirect()
may set the response body (#31886). Hence why the proposed implementation specifically looks at response headers.Response.redirect()
andNextResponse.redirect()
do not need to include the final location in their body: it is handled by next server https://github.com/vercel/next.js/blob/canary/packages/next/server/next-server.ts#L1142Because this is a breaking change, I had to adjust several tests cases, previously returning JSON/stream/text bodies. When relevant, these middlewares are returning data using response headers.
About DevEx: relying on AST analysis to detect forbidden use cases is not as good as running the code.
Such cases are easy to detect:
But these are false-positive cases:
However, I see no good reasons to let users ship middleware such as the one above, hence why the build will fail, even if technically speaking, they are not setting the response body.
Feature
fixes #number
contributing.md
Documentation / Examples
yarn lint