11
Add support for headers in functions
planned
Michael Zetterberg
A discussion at GitHub has all the details here https://github.com/gatsbyjs/gatsby/discussions/31842 and originally here https://github.com/gatsbyjs/gatsby/discussions/30735#discussioncomment-757061
Basically it would allow for better control over client caches and CDN caches to control how often functions are called and cache leading to improved handling of quota.
Activity
Newest
Oldest
S
Shruti Chaturvedula
planned
Joel Smith
Hi Michael Zetterberg, I've just updated the docs to show how you can control cache headers on Gatsby Cloud. Let me know if that takes care of your specific needs or if there's more that you'd be looking to do with headers!
Michael Zetterberg
Joel Smith: Thank you! My test function at https://gswpgatsby.gatsbyjs.io/api/hello still works as before, incorrect cache-headers. Maybe a redeploy is needed? Also I see in the docs that it says to use
res.set(...)
and not res.setHeader(...)
(which my test function uses, I will change and check again).I'm not seeing any specific mention of support for
s-max-age
either, but the statement "to ensure that functions invocations are appropriately handled when served to CDN users" seems to imply it.I will give it a new go this weekend and will report back with my findings here! Thank you for now :)
Michael Zetterberg
Joel Smith: OK I gave it a go and these are my findings. I used this repo https://gitlab.com/weahead/gswp-gatsby deployed here https://gswpgatsby.gatsbyjs.io/
- Both res.set(...)andres.setHeader(...)work (I had to redeploy though, my previously deployed function did not work). Butsetgives me "Property 'set' does not exist on type 'GatsbyFunctionResponse<any>'." in TypeScript. So I would propose to update the documentation to usesetHeaderinstead (or update the typings, but that seems more overkill).
- If calling a function from my "HOSTED ON GATSBY CLOUD" domain: https://gswpgatsby.gatsbyjs.io/ it is served through Varnish and the function is invoked correctly based on s-maxageheader. I verified this by checking the function log in admin (which by the way is real time! Awesome, what a pleasant surprise!). It does not show a new entry untils-maxagehas passed.
- stale-while-revalidatealso works as expected on the CDN level. My function has anew Date().toString()call, so I can verify the responses. I verified by invoking the function and then waitings-maxageto pass and then invoke again. It gave me a HTTP 304 stale response with anagelarger thans-maxage. Fetching again gave me a response whereagewas not 0 and the response had increased its seconds correctly. Waitings-maxage+stale-whilte-revalidateand fetching again I get a HTTP 200 with anageof 0. All good!
- Regarding stale-while-revalidate, when a stale response is returned there is no way to identify if the response is stale or not without some guess work and math. It would be nice to get ax-cache-staleheader with1or0or similar.
- I checked browser cache as well, works nice too. Forcing a refetch does trigger a revalidation (I get 304) but only on the CDN level, it does NOT trigger the function to revalidate if the function actually has any new content to return. This is precisely how I expect it all to work. So just noting it here as "documentation".
- If calling a function from my build url https://build-d6c01ead-0788-4b56-80b5-af543f47cbee.gtsb.io/ it is NOT served through Varnish and the function is NOT invoked correctly based on s-maxage. This makes sense to me as I believe there is no shared cache/reverse proxy between the client and gtsb.io deployments. Could you confirm? My gut feeling tells me this might be a nice thing, having a URL that can bypass the CDN, but of course it is up to you if that is the intended behaviour. Some users might find it unexpected, maybe explicit documentation might help clarify for them.
- Since s-maxagedoesn't apply to browser caches, you could (should?) strip it at CDN level so it isn't sent to the client. Maybe add it as an X-Stripped-Headers or something so developers can know that it is recognised but stripped.
- It is not as clear what to do with stale-while-revalidate, as browsers do support it. I wasn't expecting it on my function invocations during testing, but I think that is mainly because I'm used to how Vercel does it. I'm not sure what the "correct" way is, but I would assume that full flexibility would be allowing the developer to choose whether to strip the header in the CDN or not per function, either through configuration (in admin or code) or through code in the function itself. Having said that, personally, I have never thought of havingstale-while-revalidateheader in my client responses over at Vercel (we use it for CDN level only), given that logic I would not miss them on Gatsby Cloud.
- The responses from functions contain the x-robots-tagheader with a value ofnone. I could not find any Gatsby Cloud option or documentation on it, but this header with a value ofnonewould request search engines to not index its contents. Some users might find that unexpected. I tried to override it from the function headers but it did not work as expected. Looking at the gtsb.io deployment it shows two instances of thex-robots-tagheader, both with the value ofnone. Checking through the CDN seems to "squash" these identical headers into a single instance, which is good. What's weird though is that when I try to override it from the function I end up with two instance of thex-robots-tagheader again, but this time one has the value ofnoneand the other the value ofall(which is what I set in the function). I expect a single instance ofx-robots-tagwith the value ofall. I would like the CDN to use the headers set from the function always if possible.
- I did not try to remove any headers, so I haven't done any testing related to that. I would expect that headers from the function itself would be removable but the headers from the CDN would not be available for manipulation as they are applied after the function invocation itself.
Keep up the good work! You are doing great!
Michael Zetterberg
Joel Smith: I'm not sure my reply to myself above triggered a notification for you. So just to be on the safe side I'm replying your comment again to make sure you see my comments. Thanks!
Kyle Mathews
Michael Zetterberg: I updated the docs to use
res.setHeader
— set
is an express-ism and not as good as API as what's in node.js core already with setHeader
. 👍Thanks for the great testing! Glad it's working for the most part. Looks like some more stuff to clean up here.