Search code examples
curlnginxserverratpack

Nginx does not return 304 for "if-modified-since" header


I have a server running nginx that serves a web application built with ratpack and I can not manage to get the 304 response from when requesting the website from a browser or with curl.

Nginx conf:

location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-NginX-Proxy true;
    proxy_read_timeout 240;
    proxy_pass http://example.com/;
    proxy_redirect off;
    add_header Last-modified "Wed, 29 Nov 2017 12:56:25";
    if_modified_since   before;
}

From the browser I always get 200 ok and with curl i get

HTTP/1.1 302 Found
Server: nginx/1.6.3
Date: Wed, 29 Nov 2017 14:23:07 GMT
Content-Length: 0
Connection: keep-alive
location: http://example.com/display
Last-Modified: Wed, 29 Nov 2017 12:56:25

I have tried this two curl commands and both give the above response:

curl -I -H "If-Modified-Since: Wed,  29 Nov 2017 14:27:08" -X GET 
https://example.com

curl -I -H "If-Modified-Since: Wed,  29 Nov 2017 14:27:08" 
https://example.com

Why am I getting 302 with curl and 200 ok in the browser? What am I doing wrong? I can see that the browser is making its request with the "If-Modified-Since" header. When I reload the page resources are loaded from the browser cache, and with a hard reload all resources get a 200 ok.


Solution

  • In order for the backend application server https://example.com to generate 304 responses it will need to see the If-Modified-Since request header. In your case that header is getting to nginx but not to the application server. You need to tell nginx to pass it through. Add the following to your location block:

    proxy_set_header If-Modified-Since $http_if_modified_since;
    

    Remove if_modified_since before and add_header Last-modified. Those lines are not helpful because Last-Modified needs to be generated by the application server, rather than by your nginx proxy.

    It may be possible for the nginx proxy to take charge of whether to send 304, by unconditionally querying the application server (and doing all the work entailed in generating a response) and then deciding whether to send 304, rather than passing on the full response (probably code 200), based on the Last-Modified header in that response, but I can't see any benefit from doing it that way.

    The answers given to another question helped me to realise how little the nginx proxy knows about the freshness of dynamic content that it is proxying.