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

Running nginx 1.4.1 on ubuntu 12.10

Need to send expires header conditionally and based on mime type/content type of http response.

Added this simple piece of code inside location / {

if ($sent_http_content_type = "text/css") { 
expires 7d;
}

The expires header is not sent even if $sent_http_content_type contains "text/css"

How to fix this ?

Checking file extensions is not enough, because in my app js,css, images are being generated dynamically from php. So need to check the mime and add headers based on that too.

share|improve this question
    
Why not just match the suffix of the file name? –  jeffatrackaid Jun 13 '13 at 15:55
    
@jeffatrackaid in my application js,css, images are generated dynamically from php scripts, which wont match file extension, hence i need to add expires and other headers with mime checking. –  Silver Moon Jun 14 '13 at 3:02
    
Why would you not set the expires header in the PHP script itself? That's the right layer to do it, especially if it can change based on the type of request and content. For example, some CSS might be give an 1 hour lifetime, but others might get only 10 minutes. Your application code knows this information at runtime, nginx cannot see inside your business logic. –  rmalayter Jun 14 '13 at 16:44

3 Answers 3

$sent_http_content_type is invalid. Request header values can be accessed via $http_name. Also, for Content-type header nginx has embedded variable $content_type.

If you would like to check $content_type against bunch of types, it would be better to use map:

   map $content_type $test_header {
        "text/css"  OK;
        "text/html" OK;
        ...
        default "";
   }

   server {
        location / {
             add_header "X-Test" $test_header;
        }
   }

If $test_header evaluates to empty string, header will not be set.

For futher information, see: http://nginx.org/en/docs/http/ngx_http_core_module.html#variables http://nginx.org/en/docs/http/ngx_http_map_module.html http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header

share|improve this answer
    
thanks for that, it can be used to add a header, but I am looking for more, need to use expires, based on mime type –  Silver Moon Jun 13 '13 at 12:32
    
Do you think you could put the expires value as per each $content_type? I.e. the map could use a $content_type value of 30d or 1y and then you could place that in location / with expires $test_header? –  marksyzm Oct 22 '13 at 22:42
    
Ignore that... expires doesn't support it. However you could test against an if statement and place a hard value in expires... I'm currently having a go at that –  marksyzm Oct 22 '13 at 23:01

If you must use the mime-type, then try:

if ($content_type ~= "text/css") { 
expires 7d;
}

However, you may want to consider something like this:

location ~ \.(css|js|htc)$ {
    add_header Pragma "public";
    add_header Cache-Control "max-age=31536000, public, must-revalidate, proxy-revalidate";
         log_not_found off;
         access_log off;

}
location ~ \.(html|htm|rtf|rtx|svg|svgz|txt|xsd|xsl|xml)$ {
    add_header Pragma "public";
    add_header Cache-Control "max-age=3600, public, must-revalidate, proxy-revalidate";
         log_not_found off;
        access_log off;

}
location ~ \.(asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mp
e|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$
 {
    add_header Pragma "public";
    add_header Cache-Control "max-age=31536000, public, must-revalidate, proxy-revalidate";
         log_not_found off;
         access_log off;

}

We use this on a very busy site with very good effect.

share|improve this answer
    
i cannot test on file extension. in my application js,css and images are generated on the fly from php scripts. hence i need some mime based checking and enable expires. –  Silver Moon Jun 14 '13 at 3:01

The if directive in Nginx is processed early on at the rewrite stage, and hence the $sent_http_content_type variable has not yet been initialised - see this nginx bug report for details.

EDIT: Comparing usernames, that bug report might well be you, actually! (^_^)

Similarly, the expires directive doesn't seem to support variables in the same way that, for example, add_header does. So, since you're not in a position to statically specify the location based on file extensions, I can only think of two basic approaches.

One would be to use the map and add_header approach suggested by Vadim above to manually set HTTP headers instead of allowing the expires directive to do it. This is rather less flexible as it won't set the Expires header, but I'd hope that any browser these days would do the right thing with just Cache-Control being set. Here's an example that I've briefly tested:

map $sent_http_content_type $cacheable_types {
    "text/css"    "max-age=864000";
    "image/jpeg"  "max-age=864000";
    default       "";
}

# ...

server {
    # ...
    location / {
        # ...
        add_header "Cache-Control" $cacheable_types;
    }
}

The value 864000 is 10 days in seconds - you'll have to change this to whatever you wish. The advantage of this approach is that you can specify different times for each file type, and even override other aspects of the Cache-Control header - you discussion of this header here, and the official part from the HTTP RFC here if you prefer something more formal.

The second approach would be to just arrange that requests that will result in cacheable content all come under a specific path that you can use in a location directive like this:

location / {
    # ...
    location /static {
        expires 10d;
    }
}

This makes the nginx configuration easier because you can use its builtin expires directive, but whether it's an option very much depends whether you can enforce that pattern of URLs on your code.

share|improve this answer
    
See my comment on Vadims... had an idea... –  marksyzm Oct 22 '13 at 23:01

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.