next.js: Unable to dynamically set response headers in `page.js` components (App router)
Verify canary release
- I verified that the issue exists in the latest Next.js canary release
Provide environment information
Latest next.js app
Which area(s) of Next.js are affected? (leave empty if unsure)
App directory (appDir: true)
Link to the code that reproduces this issue or a replay of the bug
n/a
To Reproduce
Create an app/page.js file and then cry when you realize there is no way to set a response header based on data you fetched to render the page.
Describe the Bug
When using the Page router, you are able to dynamically set response headers within the getServerSideProps function since it is passed a reference to the response object. When using the App router, there is no method in which you can dynamically set a header on the response based on data fetches that occur when SSR the page. This appears to be a regression or missed feature that wasn’t migrated from the Page router.
import getProduct from '@/lib/getProduct.js';
export function getServerSideProps({ res, query }) {
const product = await getProduct(query.slug);
if (!product) return { notFound: true };
let maxAge = 86400;
if (product.saleEndDate > Date.now()) {
maxAge = Math.min(
maxAge,
Math.floor((product.saleEndDate - Date.now()) / 1000)
);
}
res.setHeader('Surrogate-Key', product.id);
res.setHeader('Surrogate-Control', `max-age=${maxAge}`);
return {
props: { product }
};
}
Expected Behavior
When using the App router, you can get a read-only copy of the request headers, but I’d expect there to be a method in which I can dynamically set the response header based on data I fetched to render the page server-side.
The main use case for us is to set the Surrogate-Key header which is used by our CDN (Fastly) to programmatically purge the cache via tagging: https://docs.fastly.com/en/guides/working-with-surrogate-keys
The only methods I see for setting response headers currently when using the App router is to apply them in the middleware or in the next.config.js. Both of these options are not aware of the data that was fetched when rendering a page so neither of them are able to set headers using data from the page.
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 56
- Comments: 33 (5 by maintainers)
We’re going to post a discussion next week with more details about setting headers outside Middleware and invite feedback on the use cases / product requirements you’re looking for 🙏
bump! Like many other people, this missing feature is the only reason I cannot use the App Router structure.
buuuuuuuuuuump!!
So the recommendation is to stuff a copy/pasted duplicate
fetchrequest for every dynamic page within your app into themiddleware.jsand have a big mapping ofurl -> fetch? That seems like a terrible solution. From an ergonomics standpoint, thepage.jsshould be able to define dynamic response headers for that page so that all logic related to the page is co-located.Have you been able to fix this? This is a massive issue.
@julianobrasil As far as I am aware, there is no way to access the response object(o.g context.res) from a page on the new App Router structure. That is the limitation at hand here. We do not have a way to modify the response headers after retrieving context during SSR for a given page.
This is massive not having this considering I was doing stuff like this before in pages:
Facing same issue, not able to migrate to app routing because of this limitation.
Data Cache and deduping is not available on the middleware.
Not being able to set headers in
page.tsis the main reason we can’t move to App router.You can rely on Next.js’s caching to de-dupe requests from Middleware and from a page.
So you’d fetch the data you are fetching from your page, within the middleware, use the response to set the cookies. Then the page should see a cache HIT when it performs the same fetch, using cached data to avoid duplicate fetches.
Having the same issue while trying to add the last-modified header dynamically!
How would I go about it if my api upstream is responsible for setting the headers? I would retrieve them out of my getInitialProps and set them based on what the API upstream was telling to set it. But I can no longer do that