Nginx + Rails + 发送文件:找不到文件

Nginx + Rails + sendfile : file not found

最近在为 nginx+rails 设置发送文件时遇到问题。我们有一种文件下载已经由 nginx 处理,我们想添加第二个规则来处理另一个位置的另一种文件,但到目前为止我们没有成功。

Ruby 控制器:

def download_file
  send_file("/srv/www/myapp/shared/tmp/directory/file.zip")
end

环境配置文件:

Rails.application.configure do
  # ..  
  config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
  # ..
end

Nginx 配置:

upstream myapp {
  server 127.0.0.1:9292;
}

server {
  listen 80;    
  server_name myapp.tld;

  client_max_body_size 10M;

  root /srv/www/myapp/current/public; 

  # This first block works perfectly
  location /__working_file {
    internal;
    alias /var/lib/myapp;
  }    

  # This second block does not work at all
  location /__new_files {
    internal;
    alias /srv/www/myapp/shared/tmp/directory;
  }

  location / {
    root /srv/www/myapp/current/public;
    try_files $uri @app;
  }

  location @app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;

    proxy_set_header X-Sendfile-Type X-Accel-Redirect;
    # This first rule works perfectly
    proxy_set_header X-Accel-Mapping /var/lib/myapp/=/__working_file/;
    # This second rule doesn't
    proxy_set_header X-Accel-Mapping /srv/www/myapp/shared/tmp/directory/=/__new_files/;

    proxy_pass_header Server;
    proxy_read_timeout 300;

    proxy_pass http://myapp;
  }
}

结果

当访问控制器操作时,send_file 命令被触发,然后我们在浏览器中得到一个 "File not found",没有下载任何东西,rails 日志显示:

Sent file /srv/www/myapp/shared/tmp/directory/file.zip (0.4ms)
Completed 200 OK in 169ms (ActiveRecord: 37.5ms)
Started GET "/srv/www/myapp/shared/tmp/directory/file.zip" for 109.190.197.126 at 2018-11-20 11:34:44 +0100

ActionController::RoutingError (No route matches [GET] "/srv/www/myapp/shared/tmp/directory/file.zip"):

该文件确实存在并且可读,但 nginx 似乎无法访问它。有什么想法吗?

在路由时它没有得到。你必须提供正确的上班路线。

问题出在两个X-Accel-Mapping的设置方式上。 Rack确实可以处理自this PR #1187合并后的几个映射。

不过到今天为止,这个PR已经合并到master上了,还没有发布(2.0.6目前是最新的版本).

唯一的问题是,设置多个映射的正确方法是使用一个 proxy_set_header 规则,并用逗号分隔每个映射,如下所示:

proxy_set_header X-Accel-Mapping, /var/lib/myapp/=/__working_file/,/srv/www/myapp/shared/tmp/directory/=/__new_files/