Safari not sending "If-Modified-Since" and "If-None-Match" headers
Asked Answered
T

3

14

I'm generating dynamic content with PHP.

I'm sending the following HTTP-header:

HTTP/1.1 304 Not Modified
Date: Sun, 09 Dec 2012 17:24:41 GMT
Server: Apache
Connection: keep-alive, Keep-Alive
Keep-Alive: timeout=1, max=100
Etag: "237f43b800e655dbe6567f7d32d34c99"
Expires: Sun, 16 Dec 2012 17:24:41 GMT
Cache-Control: max-age=604800
Vary: Accept-Encoding

I later check for the Etag to send a header('HTTP/1.1 304 Not Modified') if it matches. This works perfectly with Chrome and Firefox. However, Safari (Version 6.0.2) does not send "If-Modified-Since" and "If-None-Match" headers. This is the Request-Header sent by Safari on the second page hit:

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/536.26.17 (KHTML, like Gecko) Version/6.0.2 Safari/536.26.17
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cache-Control: max-age=0

All other files linked on that page receive the right Request-Headers and Safari used cached files or 304 where appropriate.

Why doesn't send Safari the correct Request-Header? What could I change?

Thank you!

Toomer answered 9/12, 2012 at 17:34 Comment(9)
Are you forcing a refresh via f5/refresh button? Or loading the page more normally(submitting url field w/ enter key, or clicking a link)? I ask because it sent Cache-Control: max-age=0, which smells of a refresh.Hasp
Are these the headers for the actual page being requested listed in the nav bar or a linked page such as a resource within the page? It seems that Safari doesn't check the page cache if it's the page being requested in the nav bar, but if it's a resource within another page (ajax, js, css, img), it will check the cache first.Venetian
Those are indeeed the headers generated by a "reload" (CMD+r). However accessing the site by entering it's URL lets Safari generate the same Request-Header, just without the Cache-Control-Line. What I am irritated about is that Safari NEVER sends the Date or Etag in the Request-Header but Chrome and Firefox do.Toomer
Similar issue: #5616515Chronic
The problem is too old by now to verify this but are you really sending these headers with a 304 Not Modified response or is it just a copy & paste mistake and you are sending these headers in a 200 OK?Chiao
@Chiao – I can't check now anymore. But I remember to have tried Chrome and Firefox (as stated) which worked just fine.Toomer
@Toomer Your Expires header is 2 years in the past. Im not using safari, but I would not be suprised if they disregard all other caching header you send if that header explicitly state that the image should not be cached.Chema
@Chema the first thread is two years old – the date was seven days in the future back then.Toomer
@Chiao resending these headers on a 304 response isn't bad practise, since clients have been known to 'forget' some otherwise.Warmblooded
W
4

If-Modified-Since

The notes of If-Modified-Since warn against using something different than the contents of the Last-Modified response header:

Note: If a client uses an arbitrary date in the If-Modified-Since header instead of a date taken from the Last-Modified header for the same request, the client should be aware of the fact that this date is interpreted in the server's understanding of time.

Your response doesn't contain a Last-Modified, but even if it did, nothing in the spec says that user agents MUST or SHOULD send If-Modified-Since, they just MAY.

If-None-Match

As to why Safari doesn't send an If-None-Match beats me; your ETag looks valid.

Enforcing Caching in general

Again in general nothing in the spec says you MUST cache, just that when you do, you MUST obey Cache-Control. So it's a bit of an asymmetric relation, you can enforce (transparent) caches to recheck with the origin server, but as an origin server, you can't enforce useragents to cache.

What can I do about it?

Safari is only partly free software. So nothing much, if adding a Last-Modified doesn't help.

Warmblooded answered 24/4, 2014 at 15:43 Comment(1)
I ran into the same issue concerning the If-Modified-Since header and was able to get Safari to provide it after initially returning both the Last-Modified header but also the Expires header with the same value. For more, I posted a solution on this related question, #5616515Careycarfare
E
1

I ended up solving this one by looking for what headers are sent by various big sites, and have ended up with

Last-Modified: {some date}
Cache-Control: max-age=0, must-revalidate
Expires: -1

This is working on Safari for me.

Ebeneser answered 20/4, 2016 at 8:5 Comment(3)
This works in 2020 and forces Safari to return HTTP 304 correctly.Barracoon
I could not make this work for the initial page load (details in another answer).Howdoyoudo
That's weird @JEbeneser
H
1

Safari 16.3 (March 2023) never sends If-Modified-Since or If-None-Match for the initial document GET request initiated by the browser.

Compare the request and response headers between Safari and Chrome for example.com, which uses both ETags and Last-Modified.

Safari

When reloading example.com, Safari does not send the If-Modified-Since or If-None-Matches headers.

The server must return HTTP code 200 with all content since Safari does not include caching information in the request.

Safari network request

Chrome

When reloading example.com (don't reload too quickly--Chrome interprets rapid reloads as force-reload), Chrome sends both the If-Modified-Since and If-None-Match headers populated from the first load ETag and Last-Modified headers.

The server returns HTTP code 304 since the ETag hasn't changed. Chrome network request

Howdoyoudo answered 5/4, 2023 at 21:47 Comment(3)
That's weird @Howdoyoudo (and unfortunately not that surprising). Is that a documented change? I don't have a Mac to play with, but I wonder if it's odd behaviour with devtools enabled? Sorry if I'm asking the obvious, but these things sometimes happen.Ebeneser
I had caching enabled for dev tools and I’m able to observe the behavior without dev tools open. I wasn’t able to find a bug report. There are many references to Safari’s behavior—looks like this behavior has been around since at least Safari 12: gertjans.home.xs4all.nl/javascript/cache-control.htmlHowdoyoudo
Thanks. It's surprising anything works!Ebeneser

© 2022 - 2024 — McMap. All rights reserved.