Differences between fetch() and env.ASSETS.fetch()

Is there any documentation on the differences between these two functions? I'm migrating a site from Workers to Pages (with functions), and I'm seeing test failures that I tracked down to subtle differences between how these two methods handle ETag headers. For example, it looks like fetch() will strip ETag headers by default, whereas env.ASSETS.fetch() will not. It's easy enough for me to remove the ETag header myself, but I'm concerned that there are other behavior differences that I might not be aware of.
11 Replies
Philip Walton
Philip Walton3w ago
I also just noticed that responses served from Pages functions do not contain the Cf-Cache-Status header, whereas responses served from my old Worker file did. That header was useful to determine my cache hit ratio. Is there a configuration option I can set to add that header back?
cocosrobal
cocosrobal3w ago
Cloudflare Docs
Service bindings - Runtime APIs · Cloudflare Workers docs
Facilitate Worker-to-Worker communication.
Cloudflare Docs
Fetch · Cloudflare Workers docs
An interface for asynchronously fetching resources via HTTP requests inside of a Worker.
Philip Walton
Philip Walton3w ago
Thanks for the links @cocosrobal but those resources don't cover the differences between the two fetch() methods, nor do they explain why env.ASSETS.fetch() would have different behavior when it comes to ETag and Cf-Cache-Status headers.
Philip Walton
Philip Walton3w ago
Here's an example of the headers I see when using fetch():
No description
Philip Walton
Philip Walton3w ago
And then here's an example requesting the exact same resource, but using env.ASSETS.fetch():
No description
Philip Walton
Philip Walton3w ago
Notice how the first screenshot includes the Cf-Cache-Status header (but no ETag header). And the second screenshot includes the ETag header, but no Cf-Cache-Status header. The first example also retains the X-Cache X-Cache-Hits X-Served-By and X-Timer headers from the origin server, whereas the second example strips those headers.
Walshy
Walshy3w ago
fetch is https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch ASSETS.fetch is a Pages API for fetching assets. It does not fetch an origin or anything, it's just for fetching static assets It will run through the Pages serving things so add etag, headers, handle redirects, etc.
Philip Walton
Philip Walton3w ago
ASSETS.fetch is a Pages API for fetching assets. It does not fetch an origin or anything, it's just for fetching static assets
This is not quite true, as both of the screenshots I mentioned above were from assets fetched from an external origin. So both fetch() and env.ASSETS.fetch() support that, they just have different behavior. It sounds like the answer to my question is that "no" there is no documentation that explains the difference. I'd like to suggest that there should be.
Walshy
Walshy3w ago
env.ASSETS does not fetch origins, if it does that's a problem. It runs our asset serving path which will handle everything We don't do any external fetches in that path that I'm aware of. from your description though it didn't sound like it hit an origin - if you have a url i can hit i can verify what's going on
Philip Walton
Philip Walton3w ago
Ok, I just checked with the following code:
export async function onRequestGet(context) {
return context.env.ASSETS.fetch('https://example.com');
}
export async function onRequestGet(context) {
return context.env.ASSETS.fetch('https://example.com');
}
This code doesn't error, but it looks like it actually is fetching the / path from the assets. (I.e. the "origin part of the URL is ignored and only the "pathname" part is used.) I didn't notice a difference before because my external origin had the same content as my pages account. Regarding my question about Cf-Cache-Status is threre any way to determine whether there was a cache hit when requesting an asset via env.ASSETS.fetch()? Ideally without manually implenting caching via the Cache API? ...or is the assumption that everything is a "cache hit" (even if it's located in another edge node) and the better thing to measure is the time it takes to fetch the response?
Walshy
Walshy3w ago
That's correct yes, the hostname is essentially just ignored we don't know ourselves when we get a cache hit at all times, it's something we have an open FR for But from my own metrics, we hit cache the vast majority all the time.
Want results from more Discord servers?
Add your server
More Posts
Functions always returning 404I'm having real trouble getting functions to work. - I have a functions folder in the route of my pUncaught Error: EvalError: Code generation from strings disallowed for this contextOut of the blue I started getting this error in miniflare (local dev). None of my code is calling `eTurnstileI configured my website to use turnstile but i am wondering how to make turnstile always require theCannot create a remote client: missing app tokenI got this error when deploying to Cloudflare my Astro SSR app, i have configured AstroDB token, GitD1 Best Practices dev/prod modes and --local and --remote flagsHi! What are best practices around databases with D1 for building web apps that have dev and prod mCloudflare for SaaS and Origin SSL CertificatesHello, Do our origin ssl certificates just need to be for our main zone as the origin certificates 针对反代理Github一事的回复Cloudflare团队,您好 最近我收到了有关报告URL:https://git.ikunweb.eu.org/ 疑似网络钓鱼的问题的邮件。我承认,这在很大程度上侵犯了用户的隐私,我现已将其所属的C"SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON" on authorizationWhen I tried to do "wrangler deploy" for a new project and authorizing my Cloudflare account to it, Cloudflare websites extremely slowHey, I'll try to provide as much information as I can, and everything censored can be uncensored on Hey Folks,Hey Folks, Need some help and advice, struggling a bit! I have a GA call: `ga('ec:addProduct