Search code examples
javascripthtmlcorsfetch-apipreload

Fetch request for JSON file not hitting link preload


I have an HTML preload that looks like this:

<link
  rel="preload"
  href="/_data/file.json"
  as="fetch"
  crossorigin="use-credentials"
>

(I have tried it with every permutation of the crossorigin attribute)

and then JS that looks like this:

fetch(dataPath, {
  method: 'get',
  mode: 'cors',
  credentials: 'include'
})

(I have tried it with every permutation of the mode and credentials options.)

These two lines produce identical request headers:

Request URL: http://localhost:4005/_data/file.json
Request Method: GET
Status Code: 304 Not Modified
Remote Address: [::1]:4005
Referrer Policy: strict-origin-when-cross-origin
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: localhost:4005
If-Modified-Since: Tue, 01 Aug 2023 21:24:04 GMT
If-None-Match: W/"1bdb-189b2fc9372"
Origin: http://localhost:4005
Referer: http://localhost:4005/path
Sec-Ch-Ua: "Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36

And yet I continue to get the error in Chrome and Safari:

The resource http://localhost:4005/_data/file.json was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate as value and it is preloaded intentionally.

With some crossorigin HTML attribute / fetch CORS options permutations I also get the warning:

request_json.js:11 A preload for 'http://localhost:4005/_data/file.json' is found, but is not used because the request credentials mode does not match. Consider taking a look at crossorigin attribute.

Why is the preload not being used by the browser? It seems the same thing is happening with HTTPS on production, but there the same JS isn't causing an origin header to be sent as it is locally.

I've looked at many other stack overflow questions that concern the same errors eg here, but either the solutions don't help or I don't understand what has to change, eg I don't think I'm sending a "Link HTTP-Header" but I'm not sure how.

Thanks


Solution

  • Given your JSON file is static, you shouldn't need any credentials (aka cookies). This means you can use crossorigin="anonymous" in your <link> and omit the credentials option in fetch()

    <link rel="preload" href="/_data/file.json" as="fetch" crossorigin="anonymous"/>
    
    fetch("/_data/file.json")
      .then((res) => res.json())
      .then((data) => {
        // ...
      });
    

    The fetch() defaults include method: "GET" and mode: "cors" so there's no reason to explicitly set them.


    Note that <link> tags should ideally be placed in the <head> section of your document. At the very least, they should occur before anything that attempt to use the preloaded assets.