-
Notifications
You must be signed in to change notification settings - Fork 27.4k
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
Throw error if res is accessed after gSSP returns #29010
Conversation
This comment has been minimized.
This comment has been minimized.
44837d3
to
7bd0013
Compare
This comment has been minimized.
This comment has been minimized.
Note: this PR takes on a more aggressive approach of throwing for all dev mode accesses of |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Currently it's possible to access the `ServerResponse` through `context.res` in `getServerSideProps()`. If one was to store that response and mutate its headers or status code after gSSP returns (e.g. during rendering), it would currently happen to work because of when headers are sent. However, this is an anti-pattern that relies an implementation detail of the framework and shouldn't be allowed. This will be particularly important once Next.js starts to support basic streaming (two-part flush: routing then data) because then the headers will be sent as soon as gSSP returns, which explicitly breaks this pattern. With this commit, the framework now throws an error in development mode if the ServerResponse is accessed after gSSP returns.
Stats from current PRDefault Build (Decrease detected ✓)General Overall increase
|
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
buildDuration | 14.5s | 14.7s | |
buildDurationCached | 3.7s | 3.7s | -38ms |
nodeModulesSize | 47 MB | 47 MB |
Page Load Tests Overall decrease ⚠️
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 3.067 | 3.052 | -0.02 |
/ avg req/sec | 815.07 | 819.19 | +4.12 |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 1.493 | 1.502 | |
/error-in-render avg req/sec | 1674.37 | 1664.85 |
Client Bundles (main, webpack, commons)
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
745.HASH.js gzip | 179 B | 179 B | ✓ |
framework-HASH.js gzip | 42.2 kB | 42.2 kB | ✓ |
main-HASH.js gzip | 26.6 kB | 26.6 kB | ✓ |
webpack-HASH.js gzip | 1.45 kB | 1.45 kB | ✓ |
Overall change | 70.4 kB | 70.4 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
polyfills-a4..dd70.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
_app-HASH.js gzip | 979 B | 979 B | ✓ |
_error-HASH.js gzip | 194 B | 194 B | ✓ |
amp-HASH.js gzip | 312 B | 312 B | ✓ |
css-HASH.js gzip | 329 B | 329 B | ✓ |
dynamic-HASH.js gzip | 2.67 kB | 2.67 kB | ✓ |
head-HASH.js gzip | 351 B | 351 B | ✓ |
hooks-HASH.js gzip | 918 B | 918 B | ✓ |
image-HASH.js gzip | 4.14 kB | 4.14 kB | ✓ |
index-HASH.js gzip | 261 B | 261 B | ✓ |
link-HASH.js gzip | 1.66 kB | 1.66 kB | ✓ |
routerDirect..HASH.js gzip | 318 B | 318 B | ✓ |
script-HASH.js gzip | 387 B | 387 B | ✓ |
withRouter-HASH.js gzip | 320 B | 320 B | ✓ |
bb14e60e810b..30f.css gzip | 125 B | 125 B | ✓ |
Overall change | 13 kB | 13 kB | ✓ |
Client Build Manifests
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
_buildManifest.js gzip | 492 B | 492 B | ✓ |
Overall change | 492 B | 492 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
index.html gzip | 539 B | 539 B | ✓ |
link.html gzip | 552 B | 552 B | ✓ |
withRouter.html gzip | 533 B | 533 B | ✓ |
Overall change | 1.62 kB | 1.62 kB | ✓ |
Webpack 4 Mode (Increase detected ⚠️ )
General Overall increase ⚠️
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
buildDuration | 11.9s | 11.9s | -30ms |
buildDurationCached | 5s | 4.9s | -81ms |
nodeModulesSize | 47 MB | 47 MB |
Page Load Tests Overall increase ✓
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 3.086 | 3.171 | |
/ avg req/sec | 810.01 | 788.32 | |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 1.526 | 1.463 | -0.06 |
/error-in-render avg req/sec | 1638.37 | 1709.21 | +70.84 |
Client Bundles (main, webpack, commons)
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
16.HASH.js gzip | 186 B | 186 B | ✓ |
677f882d2ed8..HASH.js gzip | 14.1 kB | 14.1 kB | ✓ |
framework.HASH.js gzip | 41.9 kB | 41.9 kB | ✓ |
main-HASH.js gzip | 13.8 kB | 13.8 kB | ✓ |
webpack-HASH.js gzip | 1.19 kB | 1.19 kB | ✓ |
Overall change | 71.2 kB | 71.2 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
polyfills-a4..dd70.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
_app-HASH.js gzip | 964 B | 964 B | ✓ |
_error-HASH.js gzip | 3.8 kB | 3.8 kB | ✓ |
amp-HASH.js gzip | 552 B | 552 B | ✓ |
css-HASH.js gzip | 333 B | 333 B | ✓ |
dynamic-HASH.js gzip | 2.87 kB | 2.87 kB | ✓ |
head-HASH.js gzip | 3.06 kB | 3.06 kB | ✓ |
hooks-HASH.js gzip | 924 B | 924 B | ✓ |
index-HASH.js gzip | 231 B | 231 B | ✓ |
link-HASH.js gzip | 1.64 kB | 1.64 kB | ✓ |
routerDirect..HASH.js gzip | 298 B | 298 B | ✓ |
script-HASH.js gzip | 3.03 kB | 3.03 kB | ✓ |
withRouter-HASH.js gzip | 295 B | 295 B | ✓ |
30809af5c834..565.css gzip | 125 B | 125 B | ✓ |
Overall change | 18.1 kB | 18.1 kB | ✓ |
Client Build Manifests
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
_buildManifest.js gzip | 500 B | 500 B | ✓ |
Overall change | 500 B | 500 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | kara/next.js res | Change | |
---|---|---|---|
index.html gzip | 585 B | 585 B | ✓ |
link.html gzip | 597 B | 597 B | ✓ |
withRouter.html gzip | 578 B | 578 B | ✓ |
Overall change | 1.76 kB | 1.76 kB | ✓ |
Failing test suitesCommit: aabd309 test/development/acceptance/ReactRefreshLogBoxMisc.test.ts
Expand output● ReactRefreshLogBox › with multiple children
● ReactRefreshLogBox › server-side only compilation errors
|
Note: Looks like failing test suite is already broken on canary: https://github.com/vercel/next.js/runs/3591780616 |
I'm getting this error on export async function getServerSideProps(ctx: NextPageContext) {
if (!ctx.req || !ctx.res) {
return { props: {} };
}
const handler = nextConnect();
handler.use(sessionMiddleware);
await handler.run(ctx.req, ctx.res);
return {
props: {},
};
} Does this change mean that using |
I'm guessing this is caused by |
I'm guessing that since |
@poacher2k The hooks that these libraries are doing only really make sense when there is another middleware that is also using the session. In a Next.js app, that will only happen if you’re using a custom server. So if you’re using a custom server, I would recommend installing the session middleware there, rather than in gSSP. If you’re not using a custom server, then you don’t actually need the hooks. With That said, this probably shouldn’t break your app, only prevent you from adopting new features. @kara it might make sense to make this a warning instead. |
In vercel#29010, we started throwing an error if the res was mutated after getServerSideProps() returned. This was to support classic streaming, where it would be possible to accidentally mutate the response headers after they were already sent. However, this change also caught [a few non-streaming cases](vercel#29010 (comment)) that we don't want to break. As such, with this change, we only throw the error if res is mutated after gSSP returns *and* you've opted into using classic streaming. Otherwise, we will only add a warning to the console.
In vercel#29010, we started throwing an error if the res was mutated after getServerSideProps() returned. This was to support classic streaming, where it would be possible to accidentally mutate the response headers after they were already sent. However, this change also caught [a few non-streaming cases](vercel#29010 (comment)) that we don't want to break. As such, with this change, we only throw the error if res is mutated after gSSP returns *and* you've opted into using classic streaming. Otherwise, we will only add a warning to the console.
In vercel#29010, we started throwing an error if the res was mutated after getServerSideProps() returned. This was to support classic streaming, where it would be possible to accidentally mutate the response headers after they were already sent. However, this change also caught [a few non-streaming cases](vercel#29010 (comment)) that we don't want to break. As such, with this change, we only throw the error if res is mutated after gSSP returns *and* you've opted into using classic streaming. Otherwise, we will only add a warning to the console.
In vercel#29010, we started throwing an error if the res was mutated after getServerSideProps() returned. This was to support classic streaming, where it would be possible to accidentally mutate the response headers after they were already sent. However, this change also caught [a few non-streaming cases](vercel#29010 (comment)) that we don't want to break. As such, with this change, we only throw the error if res is mutated after gSSP returns *and* you've opted into using classic streaming. Otherwise, we will only add a warning to the console.
In #29010, we started throwing an error if the res was mutated after getServerSideProps() returned. This was to support classic streaming, where it would be possible to accidentally mutate the response headers after they were already sent. However, this change also caught [a few non-streaming cases](#29010 (comment)) that we don't want to break. As such, with this change, we only throw the error if res is mutated after gSSP returns *and* you've opted into using classic streaming. Otherwise, we will only add a warning to the console.
Currently it's possible to access the
ServerResponse
throughcontext.res
in
getServerSideProps()
. If one was to store that response and mutateits headers or status code after gSSP returns (e.g. during rendering), it
would currently happen to work because of when headers are sent. However,
this is an anti-pattern that relies an implementation detail of the framework
and shouldn't be allowed. This will be particularly important once Next.js
starts to support basic streaming (two-part flush: routing then data) because
then the headers will be sent as soon as gSSP returns, which explicitly breaks
this pattern.
With this commit, the framework now throws an error in development mode if
the ServerResponse is accessed after gSSP returns.
Bug
fixes #number
contributing.md