Respond with another site · Cloudflare W...
Getting to the bottom of this... if a cf worker responds to the browser's request with the response from another backend request (like a reverse proxy), the zaraz injection does not work. ie: from the workers docs: https://developers.cloudflare.com/workers/examples/respond-with-another-site/
The zaraz auto injection does work if I do not modify the incoming request to the worker.
In my case I am redirecting requests to
/index.html
to actually be requests to /
because cloudflare pages responds to requests for /index.html
with a 308 redirect where I actually want to return the HTML (with zaraz script) in some cases. Perhaps there is another way for me to disable cloudflare pages 308 redirect for index.html files.... but also I've got a clear repro of where Zaraz auto-injection breaks. I imagine the zaraz worker is somehow sitting behind my worker but in front of pages in the pipeline? I don't know how the inner working of Zaraz get attached to the request pipeline... but it is skipped if I directly fetch a pages url from inside of a cf worker.Cloudflare Docs
Respond with another site · Cloudflare Workers docs
Documentation for Cloudflare Workers, a serverless execution environment that allows you to create entirely new applications or augment existing ones …
12 Replies
This is the code injected by Zaraz:
It's still loading a script tag, so I doubt there's a perf degradation for manual loading.
My understanding of worker-to-worker requests is that it is limited on an account level. I am not familiar with Zaraz's internal implementation, however, unless it is behind the scenes creating a worker on your account it should be no factor. Docs: https://developers.cloudflare.com/workers/platform/limits/#worker-to-worker-subrequests
This seems like a curious problem but as users I'm not sure how we could debug it.
Re this: I guess you're getting the benefit of not requesting the initialization script, but you still need the others.
I don't believe this is a problem with worker-to-worker requests. Zaraz works, I can request the scripts, I can submit track event, both through my worker. It's only the HTMLRewriter part of injecting the script that doesn't work. So IMO, either zaraz is being removed from the request pipeline, or some conditional logic is evaluated differently in one case than the other, or the raw html file pre-transform is being cache somewhere in cloudflare and re-served. I'm currently trying to prove there is no caching to further narrow this down.
@yo'av I've reproduced this bug very simply now - definitely in the zaraz code somewhere. If the incoming browser request accept header does not include text/html then Zaraz will not inject the zaraz script. The most basic repro case is to use postman or curl to issue a GET request to a zaraz enabled website without all the bonus headers that browsers add. Opening postman and typing in my website url and fetch the result = no zaraz script. Configure the "Accept" header in postman to "text/html" and fetch again = gets zaraz script embedded! Note an accept header of "/" will not work.
The reason this was happening on my site in a browser is because I have a service-worker in the browser that will cache my react app assets. When a service worker makes a request it uses
accept: */*
and not text/html. Note my service worker is the "out of the box" React App service worker example for caching react apps - nothing fancy.
My Suggestion: Zaraz should not be checking the incoming request accept
header but rather the outgoing response content-type
header to decide whether to inject the Zaraz script.Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Hmm... well I will look into alternative solutions for setting accept header in service worker request. But I'm not sure the accept header is reliable for the purpose above.
This would apply to probably millions of sites as React and Workbox based service worker is pretty common. But here's an official discussion on it: https://github.com/GoogleChrome/workbox/issues/3130
GitHub
Workbox should ideally use the same accept header as the browser wh...
Library Affected: workbox-sw Browser & Platform: All Issue or Feature Request Description: We noticed that workbox, when prefetching HTML documents, for example for the start-page it is using t...
Is the source code for this part of zaraz script injection open? Like part of managed components? I'd be interested to take a look.
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
This is super common. Service worker allows apps to be installed as a PWA (Progressive web app). This is very standard.
And generally reverse proxies don't change behaviour on the request but on the response. My suggestion above is also very common. But I understand you are trying to optimize for speed/efficiency.
That is why I was curious to see the source to see if you really save any real work by inspecting incoming request vs outgoing response (skipping HTML rewriter for not-applicable responses).
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Got it. I'll see how easy it is to write a workbox plugin for react app service workers to change the accept header.
If that's only a dozen lines of code or so, that might be easy enough
BTW, having Zaraz configured at the "website" level in cloudflare is also an inconvenience for things like this. We have both a www. website and an app. "website" which is an app obviously. But the config for zaraz applies to both equally which forces some compromises. If you turn of auto inject it is for all subdomains and vice versa.
You should be able to configure auto-inject using a configuration rule to scope it based on domains within your zone.
FYI, modifying the default accept header for a fetch request made from a service-worker using workbox was pretty easy. Posting this here for the benefit of anyone who searches this problem in the future and finds this thread. 🙂 The default service worker preaching for a react app (built with create-react-app or CRA) uses the
workbox-precaching
strategy for which you can addPlugins()
to manipulate the fetch requests. Hopefully this helps someone else out one day!
My Typescript: