Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I'm setting some non-caching headers in a Django middleware to control caching of xhr request. Mostly because IE is caching ajax request heavily.

class NeverCacheXhrMiddleware(object):
    """
    sets no-cache headers for all xhr requests
    xhr requests must send the HTTP_X_REQUESTED_WITH header to 
    be identified correctly as a xhr request using .is_ajax()
    see: http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers
    """
    def process_response(self, request, response):
        if request.is_ajax():
            #add_never_cache_headers(response)
            #patch_cache_control(response, no_cache=True)
            response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
            response['Pragma'] = 'no-cache'
            response['Expires'] = '0'
        return response

This works fine when I deployed my app using only Gunicorn in an dev environment. In the production environment we also run NGINX in front of Gunicorn, and it seems NGINX is overwriting the headers set by Django.

See this screenshots to see the how the headers change:

DEV Env.:

response headers in dev env.

PROD Env. with NGINX:

response headers in prod env.

Any idea what to change in the NGINX configuration in order that NGINX passes the headers set by Django?

nginx conf. looks like this:

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    sendfile        on;

    keepalive_timeout  65;

    include /path/to/sub_conf/*.conf;
}

nginx server conf. included via sub conf:

server {
    listen       80;
    server_name  localhost1;

location / {
    proxy_pass http://127.0.0.1:8000;
    }
}
share|improve this question
    
Can you post the nginx config? –  Danack May 17 '13 at 7:48
    
yes, updated the question. –  Tom May 17 '13 at 8:32

2 Answers 2

Apparently you can set proxy_ignore_headers to get Nginx to not alter your headers.

proxy_ignore_headers Cache-Control Expires Pragma;

which may be the simplest way of fixing it. What you're seeing may be caused by this feature in Nginx:

Change: now nginx does not cache by default backend responses, if they have a "Set-Cookie" header line.

Presumably they didn't do that without some reason, but I can't explain why that feature was implemented.

However if you're trying to force all caching to be disabled because "IE is caching ajax request heavily" you may have a better solution in just appending a unique number to each Ajax request, which is a more resilient way of forcing clients to not cache responses.

share|improve this answer
    
Thanks for your help. I included the following into the config. add_header Pragma "no-cache"; proxy_ignore_headers Cache-Control Expires; .... anyhow, strangely enough, after restarting nginx IE still caches the request. I knew about the possibility to add a random number to each ajax request, but adding no cache headers at the backend would be much more easy to maintain as to adjust each ajax call I do at the frontend. –  Tom May 17 '13 at 11:45
    
Looking at the headers returned, it seems as the pragma header is added, but the proxy_ignore_headers has no effect at all. –  Tom May 17 '13 at 11:51
up vote 0 down vote accepted

The issue was not that nginx was not passing the headers set in the django source, but the issue was that nginx was dropping all client headers with an underscore in them.

Since Django is looking for the HTTP_X_REQUESTED_WITH header when calling request.is_ajax(), the request was never identified as an ajax request, and consequently the no-cache headers have not been set.

def is_ajax(self):
        return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'

The issue was solved setting the underscores_in_headers to on in the nginx config. This post pointed me into the right direction.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.