18

I have a REST API behind an nginx proxy. Proxying works fine, however I am unable to cache any responses. Any help would be much appreciated:

Nginx config:

worker_processes  10;
error_log  logs/error.log;
error_log  logs/error.log  notice;
error_log  logs/error.log  info;

pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
        proxy_cache_path /path/to/cache/dir keys_zone=one:60m;
        proxy_cache_methods GET HEAD POST;

     upstream backend {
        server server1 backup;
        server server2 weight=5;
    }
    access_log  logs/access.log;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       7076;
        server_name  localhost;
        #charset koi8-r;
        access_log  logs/host.access.log;

        location / {
            add_header 'Access-Control-Allow-Origin' *;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

            proxy_cache one;
            proxy_cache_key $host$uri$is_args$args;

            add_header X-Proxy-Cache $upstream_cache_status;

            proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie;
            proxy_ignore_headers Set-Cookie;
            proxy_ignore_headers Cache-Control;

            proxy_hide_header Cache-Control;
            proxy_hide_header Set-Cookie;
            proxy_pass http://backend;
        }
    }
}

No matter what I have tried, the Proxy-Cache always comes back as a MISS:

Request Headers are:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:nginxserver:portnumber
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36

Reponse Headers are:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type,Accept
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:*
Connection:keep-alive
Content-Type:text/plain;charset=UTF-8
Date:Wed, 15 Oct 2014 16:30:18 GMT
Server:nginx/1.7.4
Transfer-Encoding:chunked
X-Proxy-Cache:MISS

My suspicion is that it's something with the client headers, but even if I issue the call via curl and check out the headers, there is no response.

Thanks in advance

nick_v1
  • 365
  • 2
  • 3
  • 11
  • 1
    In the request header: `Cache-Control:max-age=0` ...that implies "don't cache this request." – Nathan C Oct 15 '14 at 16:38
  • 1
    Is there a way for me to ignore that in the client header? This doesn't explain why it doesn't work through curl either though.... – nick_v1 Oct 15 '14 at 16:50
  • @user2630270 What's the initial request URL & method ? What's the intermediate response ? – Xavier Lucas Oct 15 '14 at 16:57
  • @XavierLucas the methods for the headers above are GET since I am now troubleshooting the issue Chrome. The request is something along the lines of http://nginxserver:port/solr/asd/select?q=*:*. I don't know how to capture intermediate response. Where can I find instructions on this? – nick_v1 Oct 15 '14 at 17:01
  • If I hit the application directly without going through nginx, with the exactly same query I get the following response headers: Content-Type: text/plain;charset=UTF-8 Transfer-Encoding: chunked – nick_v1 Oct 15 '14 at 17:07
  • @NathanC By default nginx ignore cache-control headers in requests. – Xavier Lucas Oct 15 '14 at 17:16
  • That is what I read as well, but can't confirm. Keep in mind that I am not able to get anything to cache, 0, zip, nada. I think it's an underlying problem with my config. Can you guys give it a second look? First time nginx user.... – nick_v1 Oct 15 '14 at 17:18

2 Answers2

49

You didn't tell NGINX for how much time the response is valid and must be served from cache.

This must be specified with proxy_cache_valid directive.

proxy_cache one;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 10m;

But, this won't work for POST requests because you have no cache key that differs from a POST request to another on the same URL if they don't have same content.

So you will need to adjust the cache key to $host$request_uri|$request_body. You will have to monitor the cache size (proxy_cache_path parameter max_size) and proxy response buffer proxy_buffer_size so it suits your needs.

Maroun
  • 3
  • 7
Xavier Lucas
  • 12,815
  • 2
  • 44
  • 50
  • 1
    Nice, Thanks man! It worked. Wish it was documented somewhere a bit more explicitly. – nick_v1 Oct 15 '14 at 17:39
  • If this directive is not set then any response will be cached. But the one is overriden by the header X-Accel-Expire, Cache-Control or Expire of the app. At least, Set-Cookie and Vary could avoid the cache. These facts are exposed in the doc. I created a simple script to test because my framework, Laravel, always send the above headers. – Victor Aguilar Mar 22 '17 at 15:11
  • This worked Xiavier Lucas. Thanks. I also added a difference cache time value for different HTTP codes : proxy_cache_valid 200 302 10m; ////// proxy_cache_valid 404 1m; – Deunz Mar 09 '20 at 13:50
  • This is it. How would we find this out from documentation? Good question. Maybe by looking at what options have no default (`Default: —`), which would suggest they need configuring before anything useful happens... – Marki Sep 29 '20 at 00:29
17

From: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_valid

Syntax: proxy_cache_valid [code ...] time;

...

Parameters of caching can also be set directly in the response header. This has higher priority than setting of caching time using the directive.

  • The “X-Accel-Expires” header field sets caching time of a response in seconds. The zero value disables caching for a response. If the value starts with the @ prefix, it sets an absolute time in seconds since Epoch, up to which the response may be cached.
  • If the header does not include the “X-Accel-Expires” field, parameters of caching may be set in the header fields “Expires” or
    “Cache-Control”.
  • If the header includes the “Set-Cookie” field, such a response will not be cached.
  • If the header includes the “Vary” field with the special value “*”, such a response will not be cached (1.7.7). If the header includes
    the “Vary” field with another value, such a response will be cached
    taking into account the corresponding request header fields (1.7.7).

Processing of one or more of these response header fields can be disabled using the proxy_ignore_headers directive.

Most web apps set Set-Cookie header, so a response will not be cached. To fix that, use this directive:

proxy_ignore_headers Set-Cookie;
Hieu
  • 311
  • 3
  • 4