Skip to content

Commit ead10f1

Browse files
authored
Fix handling for 204 status code with a body (#28479)
This ensures we handle 204 and 304 status codes correctly in API routes. ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [x] Errors have helpful link attached, see `contributing.md` Fixes: #28464
1 parent f216855 commit ead10f1

File tree

5 files changed

+89
-0
lines changed

5 files changed

+89
-0
lines changed

errors/invalid-api-status-body.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
Invalid API Route Status/Body Response
2+
3+
#### Why This Error Occurred
4+
5+
In one of your API routes a 204 or 304 status code was used as well as sending a response body.
6+
7+
This is invalid as a 204 or 304 status code dictates no response body should be present.
8+
9+
#### Possible Ways to Fix It
10+
11+
Send an empty body when using a 204 or 304 status code or use a different status code while sending a response body.
12+
13+
Before
14+
15+
```js
16+
export default function handler(req, res) {
17+
res.status(204).send('invalid body')
18+
}
19+
```
20+
21+
After
22+
23+
```js
24+
export default function handler(req, res) {
25+
res.status(204).send()
26+
}
27+
```
28+
29+
### Useful Links
30+
31+
- [204 status code documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204)
32+
- [304 status code documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304)

errors/manifest.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,10 @@
454454
{
455455
"title": "next-config-error",
456456
"path": "/errors/next-config-error.md"
457+
},
458+
{
459+
"title": "invalid-api-status-body",
460+
"path": "/errors/invalid-api-status-body.md"
457461
}
458462
]
459463
}

packages/next/server/api-utils.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,22 @@ export function sendData(
258258
return
259259
}
260260

261+
// strip irrelevant headers/body
262+
if (res.statusCode === 204 || res.statusCode === 304) {
263+
res.removeHeader('Content-Type')
264+
res.removeHeader('Content-Length')
265+
res.removeHeader('Transfer-Encoding')
266+
267+
if (process.env.NODE_ENV === 'development' && body) {
268+
console.warn(
269+
`A body was attempted to be set with a 204 statusCode for ${req.url}, this is invalid and the body was ignored.\n` +
270+
`See more info here https://nextjs.org/docs/messages/invalid-api-status-body`
271+
)
272+
}
273+
res.end()
274+
return
275+
}
276+
261277
const contentType = res.getHeader('Content-Type')
262278

263279
if (body instanceof Stream) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function handler(req, res) {
2+
if (req.query.invalid) {
3+
// test the warning when content is added for a 204 response
4+
return res.status(204).json({ hello: 'world' })
5+
}
6+
return res.status(204).send()
7+
}

test/integration/api-support/test/index.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,36 @@ let mode
2626
let app
2727

2828
function runTests(dev = false) {
29+
it('should handle 204 status correctly', async () => {
30+
const res = await fetchViaHTTP(appPort, '/api/status-204', undefined, {
31+
redirect: 'manual',
32+
})
33+
expect(res.status).toBe(204)
34+
expect(res.headers.get('content-type')).toBe(null)
35+
expect(res.headers.get('content-length')).toBe(null)
36+
expect(res.headers.get('transfer-encoding')).toBe(null)
37+
38+
const stderrIdx = stderr.length
39+
const res2 = await fetchViaHTTP(
40+
appPort,
41+
'/api/status-204',
42+
{ invalid: '1' },
43+
{
44+
redirect: 'manual',
45+
}
46+
)
47+
expect(res2.status).toBe(204)
48+
expect(res2.headers.get('content-type')).toBe(null)
49+
expect(res2.headers.get('content-length')).toBe(null)
50+
expect(res2.headers.get('transfer-encoding')).toBe(null)
51+
52+
if (dev) {
53+
expect(stderr.substr(stderrIdx)).toContain(
54+
'A body was attempted to be set with a 204 statusCode'
55+
)
56+
}
57+
})
58+
2959
it('should render page', async () => {
3060
const html = await renderViaHTTP(appPort, '/')
3161
expect(html).toMatch(/API - support/)

0 commit comments

Comments
 (0)