Nginx – Content disposition header on Nginx

http-headersnginx

I am doing a setup where Apache runs the web application and NginX serves files that users download. The files should be downloaded with their real names instead of the names their are being stored with. The real names are retrieved from a database.
I do not understand why am I failing to force NginX to download the files with their real names.
I send the following headers in php from Apache to NginX:

header('Location: ' . "http://nginx.mysite.com:8080/" . $file['upload_id']);
header('Content-type: ' . $this->mime);
header('Content-Disposition: attachment; filename="' . $file['file_name'] . '"');
header('Last-Modified: ' . date('D, d M Y H:i:s \G\M\T' , $this->data_mod));

It looks like NginX ignores the content-disposition header? Or am I failing in the syntax?

Edit:Output of

curl --head http://…/your/file.ext

is as follows:

HTTP/1.1 200 OK
Server: nginx/1.0.5
Date: Sat, 16 Feb 2013 14:26:33 GMT
Content-Type: application/octet-stream
Content-Length: 38807550
Last-Modified: Sun, 06 Jan 2013 14:37:36 GMT
Connection: keep-alive
Accept-Ranges: bytes

Best Answer

nginx isn't going to know it needs to return the header just because the header was return from Apache. The request to Apache is going to return that header, but you're also telling the client to go fetch that file from nginx, and nginx isn't going to receive that header nor know to send it back unless you have something in the nginx configuration to do that.

Here's the way it's working now (... represents other headers unimportant to this discussion):

Request to Apache

GET /your/file.ext HTTP/1.1
Host: apache.mysite.com
...

Response from Apache

HTTP/1.1 302 Redirect
Location: http://nginx.mysite.com:8080/fileid
Content-Disposition: attachment; filename="filename"
...

When your web client receives this, it's basically being told to go somewhere else. That's going to initiate a new request:

Request to nginx

GET /fileid HTTP/1.1
Host: nginx.mysite.com
...

Response from nginx

HTTP/1.1 200 OK
... (no Content-Disposition header)

You need to have the nginx response return the Content-Disposition header, not the Apache/PHP response. You have a few options here:

  • Pass the nginx request through to a script that will translate the fileid form to the file.ext form, send back the Content-Dispotion: header and return the data (this is very similar to your PHP script, except it also needs to return the file data).
  • Request the file.ext form from nginx and configure nginx to always add a Content-Disposition: header with the filename= portion set the file.ext of the request.
  • Update your PHP script to proxy the nginx request internally, so that rather than returning the Location: header and subsequent redirect, it returns the header it needs, then fetches the data from nginx internally and dumps it out to the client.

The second option seems cleanest to me, but your setup may not support it.