Rails使用send_file发送0字节文件 [英] Rails sends 0 byte files using send_file

查看:92
本文介绍了Rails使用send_file发送0字节文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法使send_file(Model.attachment.path)工作. 它不会失败,而是向客户端发送一个0字节大小的文件,尽管文件名正确.

当我从Rails 2.3.8迁移到3后,这个问题开始发生.

此迁移中发生了很多其他事情,我将尽力详细说明所有这些事情.

  1. 分布更改/服务器更改. Rackspace RHEL5到Linode Ubuntu 10.04LTS
  2. Ruby版本更改,从1.8.6-> 1.9.2
  3. Rails版本更改,版本2.3.8-> 3.0.0
  4. httpd平台更改,apache2-> nginx(但是我也尝试过apache2,但它不起作用).

我通过ftp移动了附件,因为它们不是我的git存储库的一部分,所以它们通过cap deploy发布,而是手动将ftp remote(RHEL5)移到local(Win7),然后将local(Win7)移到remote(Ubuntu10). /p>

我确实知道FTPing不会通过传输保留文件权限,因此我所做的也是模仿以前服务器上看到的chmod,因此它们几乎相同. (用户/组不同,设置为root:root而不是olduser:olduser).

从我的生产日志中下载附件的请求的摘录.

Started GET "/attachments/replies/1410?1277105698" for 218.102.140.205 at 2010-09-16 09:44:31 +0000
  Processing by AttachmentsController#replies as HTML
  Parameters: {"1277105698"=>nil, "id"=>"1410"}
Sent file /srv/app/releases/20100916094249/attachments/replies/UE0003-Requisition_For_Compensation_Leave.doc (0.2ms)
Completed 200 OK in 78ms

一切都很好.让我也排除本地问题,我尝试在Win7和Ubuntu(在Vbox上)上通过Chrome下载.

让我也向您保证,路径确实是正确的.

root@li162-41:/srv/app/current# tail /srv/app/releases/20100916094249/attachments/replies/UE0003-Requisition_For_Compensation_Leave.doc
#
    #
         %17nw
                 HQ��+1ae����
                                             %33333333333(��QR���HX�"%%��@9
��@�p4��#P@��Unknown������������G��z �Times New Roman5��Symbol3&�
                       �z �Arial5&�

因此,总而言之,如何使send_file实际发送文件而不是伪造的0字节垃圾.

解决方案

send_file具有:x_sendfile参数,该参数在Rails 3中默认为true. 通过返回带有路径的X-Sendfile标头的空响应,此功能将流下载下载卸载到前端服务器-Apache(带有mod_xsendfile)或lighttpd.

Nginx使用X-Accel-Redirect标头来实现相同的功能,但是您必须 在适当的环境文件中正确配置Rails:

config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

更新3次:该行已存在于production.rb中,只需取消注释即可.

sendfile on;添加到您的nginx配置中,以利用Rails发送的标头. 请记住,必须使用绝对路径,并且nginx必须具有对文件的读取权限.

别名文件的另一种方法:

为了提高安全性,我在nginx中使用别名代替绝对路径, 但是send_file方法检查是否存在以别名失败的文件. 因此,我将操作更改为:

  head(
        'X-Accel-Redirect'=> file_item.location,
        'Content-Type' => file_item.content_type,
        'Content-Disposition' => "attachment; filename=\"#{file_item.name}\"");
  render :nothing => true;

I can't get send_file(Model.attachment.path) to work. It doesn't fail, instead, it sends a 0 byte size file to the client, the file names are correct though.

This problem started happening after I did a big migration from Rails 2.3.8 to 3.

There were a lot of other things that took place in this migration and I will try my best to detail all of them.

  1. Distrubution change/Server Change. Rackspace RHEL5 to Linode Ubuntu 10.04LTS
  2. Ruby version change, 1.8.6 -> 1.9.2
  3. Rails version change, 2.3.8 -> 3.0.0
  4. httpd platform change, apache2 -> nginx (However I tried on apache2 as well and it did not work).

I moved the attachments via ftp as they were not part of my git repositories so they were published via cap deploy, instead manual ftp remote(RHEL5) to local(Win7) then local(Win7) to remote(Ubuntu10).

I do know that FTPing does not retain the file permissions through the transfers, so what I've also done is mimicked the chmods that were seen on my previous servers so they are almost identical. (users/groups are different, set to root:root instead of olduser:olduser).

A snippet of the request to download a attachment from my production log.

Started GET "/attachments/replies/1410?1277105698" for 218.102.140.205 at 2010-09-16 09:44:31 +0000
  Processing by AttachmentsController#replies as HTML
  Parameters: {"1277105698"=>nil, "id"=>"1410"}
Sent file /srv/app/releases/20100916094249/attachments/replies/UE0003-Requisition_For_Compensation_Leave.doc (0.2ms)
Completed 200 OK in 78ms

Everything's okay. Let me also rule out local issues, I've tried downloading via Chrome on both Win7 and Ubuntu (on Vbox).

Let me also assure you that the path is indeed correct.

root@li162-41:/srv/app/current# tail /srv/app/releases/20100916094249/attachments/replies/UE0003-Requisition_For_Compensation_Leave.doc
#
    #
         %17nw
                 HQ��+1ae����
                                             %33333333333(��QR���HX�"%%��@9
��@�p4��#P@��Unknown������������G��z �Times New Roman5��Symbol3&�
                       �z �Arial5&�

So to sum up the question, how do I get send_file to actually send files instead of fake 0 byte junk.

解决方案

send_file has :x_sendfile param which defaults to true in Rails 3. This feature offloads streaming download to front server - Apache (with mod_xsendfile) or lighttpd, by returning empty response with X-Sendfile header with path.

Nginx uses X-Accel-Redirect header for same functionality but you have to configure Rails properly in proper environment file:

config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

Rails 3 update: this line already exists in production.rb, just uncomment it.

Add sendfile on; to your nginx config to utilize header sent by Rails. Remember the absolute path must be used and nginx must have read access to file.

Another way for aliased files:

For better security I use aliases in nginx instead of absolute paths, however send_file method checks existence of file which fails with alias. Thus I changed my action to:

  head(
        'X-Accel-Redirect'=> file_item.location,
        'Content-Type' => file_item.content_type,
        'Content-Disposition' => "attachment; filename=\"#{file_item.name}\"");
  render :nothing => true;

这篇关于Rails使用send_file发送0字节文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆