From 3f164abd25e820ef337550b53f9a8994fb38b36e Mon Sep 17 00:00:00 2001 From: Shohei Maeda <11495867+smaeda-ks@users.noreply.github.com> Date: Sun, 28 May 2023 21:44:11 +0900 Subject: [PATCH] Add `cache-control` header on 304 response (#50408) Next.js currently does not return `cache-control` header on 304 response. Accordingly to RFC, Next.js should include it as well: https://www.rfc-editor.org/rfc/rfc9110#section-15.4.5 > The server generating a 304 response MUST generate any of the following header fields that would have been sent in a [200 (OK)](https://www.rfc-editor.org/rfc/rfc9110#status.200) response to the same request: > > - [Content-Location](https://www.rfc-editor.org/rfc/rfc9110#field.content-location), [Date](https://www.rfc-editor.org/rfc/rfc9110#field.date), [ETag](https://www.rfc-editor.org/rfc/rfc9110#field.etag), and [Vary](https://www.rfc-editor.org/rfc/rfc9110#field.vary) > - **_Cache-Control_** and Expires (see [[CACHING](https://www.rfc-editor.org/rfc/rfc9110#CACHING)]) --- packages/next/src/server/send-payload/index.ts | 8 ++++---- .../prerender-revalidate/pages/static.js | 18 ++++++++++++++++++ .../prerender-revalidate/test/index.test.js | 13 +++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 test/integration/prerender-revalidate/pages/static.js diff --git a/packages/next/src/server/send-payload/index.ts b/packages/next/src/server/send-payload/index.ts index 1290a82fdbaa3..ed6982f681fab 100644 --- a/packages/next/src/server/send-payload/index.ts +++ b/packages/next/src/server/send-payload/index.ts @@ -63,6 +63,10 @@ export async function sendRenderResult({ res.setHeader('X-Powered-By', 'Next.js') } + if (options != null) { + setRevalidateHeaders(res, options) + } + const payload = result.isDynamic() ? null : await result.toUnchunkedString() if (payload !== null) { @@ -91,10 +95,6 @@ export async function sendRenderResult({ res.setHeader('Content-Length', Buffer.byteLength(payload)) } - if (options != null) { - setRevalidateHeaders(res, options) - } - if (req.method === 'HEAD') { res.end(null) } else if (payload !== null) { diff --git a/test/integration/prerender-revalidate/pages/static.js b/test/integration/prerender-revalidate/pages/static.js new file mode 100644 index 0000000000000..ffb385842002c --- /dev/null +++ b/test/integration/prerender-revalidate/pages/static.js @@ -0,0 +1,18 @@ +export async function getStaticProps() { + return { + props: { + world: 'world', + }, + revalidate: 10, + } +} + +const Page = ({ world }) => { + return ( +
+

hello {world}

+
+ ) +} + +export default Page diff --git a/test/integration/prerender-revalidate/test/index.test.js b/test/integration/prerender-revalidate/test/index.test.js index c2203d27d2b6c..63e3286536594 100644 --- a/test/integration/prerender-revalidate/test/index.test.js +++ b/test/integration/prerender-revalidate/test/index.test.js @@ -9,6 +9,7 @@ import { renderViaHTTP, waitFor, getPageFileFromPagesManifest, + fetchViaHTTP, } from 'next-test-utils' import { join } from 'path' @@ -79,6 +80,18 @@ describe('SSG Prerender Revalidate', () => { runTests('/named', '/named') runTests('/nested', '/nested') runTests('/nested/named', '/nested/named') + + it('should return cache-control header on 304 status', async () => { + const url = `http://localhost:${appPort}` + const res1 = await fetchViaHTTP(url, '/static') + const cacheControl200 = res1.headers.get('Cache-Control') + const etag = res1.headers.get('ETag') + + const headers = { 'If-None-Match': etag } + const res2 = await fetchViaHTTP(url, '/static', undefined, { headers }) + const cacheControl304 = res2.headers.get('Cache-Control') + expect(cacheControl304).toEqual(cacheControl200) + }) }) // Regression test for https://github.com/vercel/next.js/issues/24806