I enabled SXG on my website. The Signed Exchange of HTML is correctly prefetched in Google results or on prefetch page (https://signed-exchange-testing.dev/prefetch). However, subresources are prefetched - in the best case - only partially. And partial prefetching of subresources in SXG means no subresources will be actually used due to privacy reasons (https://github.com/WICG/webpackage/blob/main/explainers/signed-exchange-subresource-substitution.md). So I’m left with prefetching HTML only.
Here is a demo SXG-enabled page: https://www.planujemywesele.pl/experiments/worker_tests/10
It correctly generates SXG when asked for. It includes subresources with signatures. The main document gets cached by webpkgcache.com, when I use SXG validator Chrome extension (https://chrome.google.com/webstore/detail/sxg-validator/hiijcdgcphjeljafieaejfhodfbpmgoe).
However, when I try to preload it using prefetch page (https://signed-exchange-testing.dev/prefetch/https://www.planujemywesele.pl/experiments/worker_tests/10), I get CORS errors for the resources:
I found the CORS errors happen because the resource being prefetched doesn’t exist in webpkgcache.com and it returns HTML with a client-side redirect to the actual resource:
The browser gets HTML instead of the SXG version of the subresource. This HTML response doesn’t contain “Access-Control-Allow-Origin” header, and this causes the CORS error.
How to put subresources into webpkgcache.com? I would appreciate any help.
I have some more info to share. I installed Cloudflare worker proxy to intercept and log requests. This way I can log what Googlebot does. Specifically, I was interested if Googlebot downloads subresources. And it does!
"request": {
"url": "https://www.planujemywesele.pl/experiments/worker_tests/10.gif",
"method": "GET",
"headers": {
"accept": "*/*;q=0.8,application/signed-exchange;v=b3",
"cf-connecting-ip": "66.249.65.67",
"cf-ipcountry": "US",
"cf-ray": "81cadc774a250b76",
"cf-rum-ctag": "sxg_enabled",
"cf-visitor": "{\"scheme\":\"https\"}",
"user-agent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.117 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
"via": "sxgrs"
},
As you can see in the above log excerpt, the user agent contains the "Googlebot" substring. It asks specifically for the "application/signed-exchange" content type.
The other idea was to test the URL using a live-inspection tool from Google Search Console.
Here are the HTTP headers of the response Googlebot got from Cloudflare. It clearly contains all subresources.
HTTP/1.1 200 OK
age: 33
cache-control: max-age=600, public
cf-as-number: 15169
cf-cache-status: HIT
cf-ray: 81cae9acb3fa2c94-DFW
content-encoding: mi-sha256-03
content-type: text/html; charset=utf-8
date: Fri, 27 Oct 2023 12:23:53 GMT
digest: mi-sha256-03=QIzS1L5UIW6WLMF0haik9lJ5aGjaGa5eeQBwkPcdZhw=
link: <https://www.planujemywesele.pl/experiments/worker_tests/10.gif>;as=image;rel=preload,<https://www.planujemywesele.pl/experiments/worker_tests/10.gif>;rel=allowed-alt-sxg;header-integrity="sha256-KyBKX3EuDQ+G9fHfffaHoEgLGU6IJgPouhtlLZMTQ3M=",<https://www.planujemywesele.pl/experiments/worker_tests/10.svg>;as=image;rel=preload,<https://www.planujemywesele.pl/experiments/worker_tests/10.svg>;rel=allowed-alt-sxg;header-integrity="sha256-NqWoVvKrYhz0C0ScoQTIQu5gPqx5ivG2ZRbVm2nXHUk=",<https://www.planujemywesele.pl/experiments/worker_tests/10.jpeg>;as=image;rel=preload,<https://www.planujemywesele.pl/experiments/worker_tests/10.jpeg>;rel=allowed-alt-sxg;header-integrity="sha256-5S5BVKziDyaapTTcFpVM4yo1worif9jiL2/alEyLFyQ=",<https://www.planujemywesele.pl/experiments/worker_tests/10.css>;as=style;rel=preload,<https://www.planujemywesele.pl/experiments/worker_tests/10.css>;rel=allowed-alt-sxg;header-integrity="sha256-d4HNY6uGf25QgAB7vg4p9agBoZsUZ9WTg0oMEKvUGLE=",<https://www.planujemywesele.pl/experiments/worker_tests/10.js>;as=script;rel=preload,<https://www.planujemywesele.pl/experiments/worker_tests/10.js>;rel=allowed-alt-sxg;header-integrity="sha256-lwJjHKH3bwisNomE3Qs4818TTdhN+FuVcLwGiDp948M="
referrer-policy: origin-when-cross-origin
server: cloudflare
status: 200 OK
x-app-id: 1
x-content-type-options: nosniff
x-download-options: noopen
x-frame-options: SAMEORIGIN
x-request-id: 7753979e-9dd1-4d1a-99dd-6c675f521449
x-xss-protection: 1; mode=block
I have 2 js subresources. One is correctly saved to webpkgcache.com, while the other is not.
The HTTP headers of resources differ. Maybe some headers are problematic? However, I don’t see any prohibited headers from Cloudflare documentation here.
Good headers (url: https://www.planujemywesele.pl/scripts-proxy/gtag.js?id=G-60MLFKYS4J):
tl;dr: disable etags for static assets, set Vary header to Accept-Encoding, disable Enhanced HTTP/2 Prioritization or route static assets through a worker.