You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue isn't strictly a bug in Rack::Cache, but it's a problem that can very easily come up when using Rack::Cache with Rails. Not sure what the best solution is, but thought I'd raise the issue and see what you thought.
It's very easy to recreate the problem:
Create a new Rails app. Use the asset pipeline. Put something into one of your assets.
Add Rack::Cache as directed in config/application.yml:
config.middleware.use(Rack::Cache)
Start your Rails server in development mode.
Load a page, receive asset.
In a fresh cache (i.e. a new Chrome incognito window), load the same page a second time. This time the asset request wrongly returns a 304 and empty body, thus the asset is not received.
Here's why it happens (to the best of my understanding):
The Rails middleware stack includes Rack::ConditionalGet, and this resides higher on the stack than Rack::Cache (which is added near the end). ConditionalGet sees the request for the asset and forwards it along.
Rack::Cache receives the request (because of the asset pipeline, asset requests travel the whole stack in development). It needs to check if its cached version is fresh, so it adds HTTP_IF_MODIFIED_SINCE and HTTP_IF_NONE_MATCH headers to the request env and forwards it along.
Rails agrees that yeah, that's fresh, so Rack::Cache correctly builds a 200 response using its cached copy. It passes things back up the stack to Rack::ConditionalGet, which now looks at the env, sees that the caching headers are set (because Rack::Cache set them earlier), and thinks those are browser headers. So it decides to return a 304 to the poor browser, who never indicated that it had anything cached.
If Rack::Cache gets to do its business first, everything goes according to plan, and the two middlewares play much nicer together.
So... is this Rack::Cache's fault for dirtying up @env? Or Rack::ConditionalGet's fault for looking at the env at a weird time and assuming it came from the browser? Or is this just a documentation issue?
The text was updated successfully, but these errors were encountered:
Hmm, teah Rack::Cache should definitely come before Rack::ConditionalGet in the middleware stack IMO. I thought it was like this originally. I wonder if something changed there.
This issue isn't strictly a bug in Rack::Cache, but it's a problem that can very easily come up when using Rack::Cache with Rails. Not sure what the best solution is, but thought I'd raise the issue and see what you thought.
It's very easy to recreate the problem:
Create a new Rails app. Use the asset pipeline. Put something into one of your assets.
Add Rack::Cache as directed in
config/application.yml
:Start your Rails server in development mode.
Load a page, receive asset.
In a fresh cache (i.e. a new Chrome incognito window), load the same page a second time. This time the asset request wrongly returns a 304 and empty body, thus the asset is not received.
Here's why it happens (to the best of my understanding):
The Rails middleware stack includes Rack::ConditionalGet, and this resides higher on the stack than Rack::Cache (which is added near the end). ConditionalGet sees the request for the asset and forwards it along.
Rack::Cache receives the request (because of the asset pipeline, asset requests travel the whole stack in development). It needs to check if its cached version is fresh, so it adds
HTTP_IF_MODIFIED_SINCE
andHTTP_IF_NONE_MATCH
headers to the request env and forwards it along.Rails agrees that yeah, that's fresh, so Rack::Cache correctly builds a 200 response using its cached copy. It passes things back up the stack to Rack::ConditionalGet, which now looks at the env, sees that the caching headers are set (because Rack::Cache set them earlier), and thinks those are browser headers. So it decides to return a 304 to the poor browser, who never indicated that it had anything cached.
Here's how I fixed / worked around the issue:
If Rack::Cache gets to do its business first, everything goes according to plan, and the two middlewares play much nicer together.
So... is this Rack::Cache's fault for dirtying up
@env
? Or Rack::ConditionalGet's fault for looking at the env at a weird time and assuming it came from the browser? Or is this just a documentation issue?The text was updated successfully, but these errors were encountered: