Content-Length Header missing from Nginx-backed Ra

2020-07-18 08:12发布

问题:

I've a rails app that serves large static files to registered users. I was able to implement it by following the excellent guide here: Protected downloads with nginx, Rails 3.0, and #send_file. The downloads and everything else is working great, but there is just this problem - The Content-Length header isn't being sent.

It's okay for small files, but it gets really frustrating when large files are downloaded, since download managers and browsers don't show any progress. How can I fix this? Do I have to add something to my nginx configuration or do I have to pass along some other option to the send_file method in my rails controller? I have been searching online for quite some time but have been unsuccessful. Please Help! Thanks!

Here's my nginx.conf:

upstream unicorn {
  server unix:/tmp/unicorn.awesomeapp.sock fail_timeout=0;
}

server {
  listen 80 default_server deferred;
  # server_name example.com;
  root /home/deploy/apps/awesomeapp/current/public;

  location ~ /downloads/(.*) {
    internal;
    alias /home/deploy/uploads/$1;
  }

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;
  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_set_header X-Sendfile-Type X-Accel-Redirect;
    proxy_set_header X-Accel-Mapping /downloads/=/home/deploy/uploads/;

    proxy_pass http://unicorn;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 20M;
  keepalive_timeout 10;
}

回答1:

Okay, here's something. I don't know if it's the right way or not but I was able to fix the issue by manually sending the Content-Length Header from my Rails Controller. Here's what I'm doing:

def download
    @file = Attachment.find(params[:id])

    response.headers['Content-Length'] = @file.size.to_s
    send_file(@file.path, x_sendfile: true)
end

nginx should be automatically able to set the header. There must be something that I'm missing; but until I find a 'proper' solution, I guess this will have to do.

P.S: The Header needs to be a string to work properly with some webservers, hence the .to_s