Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome CORS requests are faster when cache is disabled?

My app loads a video here: https://core.arc.io/guanzo/VideoOfPeopleWalking.mp4

It loads the video from another origin in chunks of 16Kb using the Range request header. My server has set the response header Access-Control-Max-Age to 10 minutes to prevent redundant OPTIONS requests.

Visit the link (its an HTML page), open the network tools, and observe that it takes around 1s to fetch a 16Kb chunk.

Now check "Disable cache", and you should see the requests finish a LOT faster, and it looks like there are more concurrent requests. This is the opposite of expected behavior, because each request has to fire and wait for an OPTIONS request.

If the cache is enabled, requests should be faster, no? What's going on here?

Here's a reproduction in GIF form: https://i.gyazo.com/ec5941829031cdd4dc684a3b53ec6c39.mp4

NOTE: The chunks are stored in IndexedDB, so if you refresh the page, you'll need to clear IndexedDB to force all the requests to fire.

EDIT: Filter out any firestore requests, I'm not sure why those are firing but it should be unrelated to my question.

EDIT: A new clue! https://i.gyazo.com/bd887533a42868f748564ccda4451881.png

When "Disable Cache" is checked, Chrome will reuse the same TCP connection as seen in the "Connection ID" column. Ostensibly this should make requests faster.

like image 248
Eric Guan Avatar asked Sep 16 '18 00:09

Eric Guan


People also ask

How do I fix the cors problem on Chrome?

Simply activate the add-on and perform the request. CORS or Cross-Origin Resource Sharing is blocked in modern browsers by default (in JavaScript APIs). Installing this add-on will allow you to unblock this feature.


1 Answers

Taking deep breaths while poking my head out of the debugging rabbit hole.

This is the kind of problem that has many solutions.

The problem:

Chrome thinks each range request is requesting the "same" resource because the URL is the same. It's technically NOT the "same" resource because a different range of bytes is requested as specified in the Content-Range header.

Here's a quote from the chromium docs on how the http cache treats requests with the same URL.

Enforce the cache lock.

The cache implements a single writer - multiple reader lock so that only one network request for the same resource is in flight at any given time.

Note that the existence of the cache lock means that no bandwidth is wasted re-fetching the same resource simultaneously. On the other hand, it forces requests to wait until a previous request finishes downloading a resource...

If you opened the "Timing" tab in each network request in my example, you'd see that each request was waiting for the previous request to finish.

The Solution:

Force Chrome to recognize that the range requests are returning different resources.

This can be done by setting the header Cache-Control: no-cache, no-store on the request or the response. The performance improvement was highest when setting it on the request. Other header values will probably work, I only tested no-cache, no-store. This explains why checking "Disable cache" made my requests so much faster, each request was able to use a different TCP connection and wasn't stalled by the cache lock.

I'd like to give props to this SO question for giving me the "Aha!" moment, and to Firefox for not having this problem.

like image 124
Eric Guan Avatar answered Sep 24 '22 15:09

Eric Guan