Repository navigation
perf(seo): send ETags on edge cached pages and answer 304 - #636
Merged
Merged
Conversation
Edge cached HTML carried no validator, so every recrawl downloaded every page again. The Nuxt SEO crawler saw no unchanged page in seven days, and Workers Cache replaced each stale page with a full render. A page under an edgeCache rule now gets a weak ETag from the build id and a hash of its HTML. Sentry's per-render trace meta tags are left out of the hash. A request that sends the ETag back gets an empty 304 that keeps the route's cache headers. Requests with credentials and pages the edge may not store get no ETag. No page sends Last-Modified. A Skill page shows stars, ages and related Skills, so no one date bounds it, and a cache would answer If-Modified-Since with a wrong 304. The post-deploy edge cache check now proves the 304, and proves that a conditional request on a cold entry never leaves a 304 for the next visitor.
Contributor
🤖 MERGED
GitHub merged this pull request. No material findings were recorded. The pull request closed. |
1 of 6 tasks
harlan-zw
added a commit
that referenced
this pull request
Oct 13, 2026
Every deploy since #636 failed the edge cache check with `no-etag`. The Worker sends the ETag, but Cloudflare removes it from an HTML 200 while a zone feature that rewrites HTML is on, such as Email Obfuscation or Automatic HTTPS Rewrites. A 304 has no body, so it keeps the ETag. The check now asks for a 304 with `If-None-Match: *` when the page has no ETag, reads the ETag there, and runs the 304 and stored-page checks with it. A stripped ETag becomes a warning and a GitHub annotation. The deploy still fails when no response carries an ETag, or when a 304 replaces the stored page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
❓ Type of change
📚 Description
skilld's HTML carried no
ETagand noLast-Modified, so every recrawl downloaded every page again. The Nuxt SEO crawler recorded no unchanged skilld page in seven days, against about 60% on the other sites it crawls.A page under an
edgeCacherule now gets a weak ETag:W/"<build id>-<hash of the rendered HTML>". A deploy or any change to the HTML gives a new ETag. The hash leaves out Sentry'ssentry-traceandbaggagemeta tags, because they carry a new trace id on every render. A request that sends the ETag back inIf-None-Matchgets an empty 304. The 304 keeps the route's cache headers, so a Workers Cache entry that revalidates stays fresh. The Worker still renders the page on a miss or a revalidation, because the hash needs the HTML.No ETag goes on:
Authorizationheadercloudflare-cdn-cache-controllets no shared cache store itThat leaves
/, Skill pages with their repository and owner hubs,/skills/trending,/skills/demoswith its demo pages,/cliand/developers. Browsers still getcache-control: private, no-store. Google does not document whether Googlebot keeps an ETag from ano-storeresponse.No page sends
Last-Modified. A Skill page shows stars, ages and related Skills, so no one date bounds what it renders. If that date missed a change, a cache would answerIf-Modified-Sincewith a wrong 304. A request that sends onlyIf-Modified-Sincestill gets the whole page.The homepage keeps its render time in the payload (
render:now), so each render of/has its own ETag, and the Worker never answers 304 for/.pnpm production:edge-cachenow checks two more things on each page it covers after a deploy:The Workers Cache docs say the cache revalidates with the Worker through
If-None-Match. They do not say how the cache answers a client's conditional request. These two checks are the first production proof of that path.