通过 Web 服务调用时 Rails send_file 不发送数据

发布于 2024-12-05 12:37:09 字数 1799 浏览 3 评论 0原文

我处于一种奇怪的情况,send_file 无法正确发送文件。情况如下:

Rail 版本:3.0.10 和 3.1.0 [两个不同的测试分支] Ruby:RVM 上的 1.9.2 网络服务器:Apache 和 Passenger

我的客户有一个文档管理系统;我致力于将其从 Rails 2 升级到 Rails 3(现在是 Rails 3.1)。我们主要重新开发该系统,因为早期的系统已经相当旧了。除一项功能外,所有功能均正常工作。该应用程序允许用户下载分配给他们的文档。当用户登录时,他们可以看到分配给他们的文档并且可以下载。它工作得很好。下面是有效的代码:

send_file(document.file[:path],
                    :type => document.file[:content_type],:x_sendfile=>true, :filename=>document.name)

有一个客户(我的客户)已经为其制定了早期的解决方案,通过基于 .NET 的 Web 服务(或任何可能被称为的服务)请求时发送文档。 Web 服务验证用户身份,然后转发到文档下载路径。我能够使 Web 服务进行身份验证,然后重定向到下载文件的控制器操作,但它不起作用。服务器日志显示一切正常:

Started GET "/download/12234" for 12.123.12.123 at 2011-09-20 23:21:24 -0400
  Processing by DocumentController#download as HTML
  Parameters: {"id"=>"12234"}
Sent file /yyy/zzz/abc/12234 (0.1ms)
Completed 200 OK in 138ms

我已更改特定名称和 IP。请注意,IP (12.123.12.123) 用于托管 Web 服务的服务器。

我正在与开发 .NET Web 服务的开发人员通话,他说他得到的所有标头都是正确的,除了内容长度为 -1 并且他没有收到任何内容。他说所有其他标题都是正确的。

解决问题;我通过尝试设置所有可能的选项(x_sendfile、流、处置等)尝试了 send_file 的多种变体。我还尝试设置标头:

response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"

但是当我使用 Web 服务下载文件时,没有任何效果。但是,相同的方法可以直接在浏览器中工作[我通过绕过代码中的身份验证进行测试]。

我尝试使用 send_date,但它不起作用:

File.open(document.file[:path], 'r') do |f|
send_data f.read, :type => document.file[:content_type], :filename => document.name, :disposition => 'inline'
end

作为解决方法,我尝试使用 redirect_to 而不是发送文件,并在公共文件夹中使用测试文件,它可以工作。虽然不安全,但这似乎工作正常。唯一的问题是浏览器现在正在打开文档而不是下载它。

请帮我。

更新:该问题与 Rails 现在发送分块内容以及 Web 服务期望内容长度这一事实有关。

I am in a strange situation where send_file is unable to send file correctly. Here is situation:

Rail version: 3.0.10 and 3.1.0 [two different branches for testing]
Ruby: 1.9.2 on RVM
Webserver: Apache with Passenger

My client has a document management system; I worked on upgrading it to Rails 3 (and now rails 3.1) from Rails 2. We mostly redeveloped the system as the earlier one was quite old. All the features are working except one. The application allows users to download documents assigned to them. When users login they can see which documents are assigned to them and they can download. It works perfectly fine. Here is the code which works:

send_file(document.file[:path],
                    :type => document.file[:content_type],:x_sendfile=>true, :filename=>document.name)

There is one client for which they (my client) have made their earlier solution to send the document when requested through a .NET based web service (or whatever it may be called). The web service authenticates as a user and then is forwarded to document download path. I am able to make the web service authenticate and then redirect to the controller action which downloads the files but it does not work. The Server log says everything is ok:

Started GET "/download/12234" for 12.123.12.123 at 2011-09-20 23:21:24 -0400
  Processing by DocumentController#download as HTML
  Parameters: {"id"=>"12234"}
Sent file /yyy/zzz/abc/12234 (0.1ms)
Completed 200 OK in 138ms

I have changed the specific names and IPs. Note that the IP (12.123.12.123) is for the server which hosts web service.

I was on call with the developer who developed the .NET web service and he says he getting all the headers correct except that the content length is -1 and he is receiving no content. He said all other headers are correct.

To solve the problem; I tried multiple variations of send_file by trying to set all possible options (x_sendfile, stream, disposition etc).. I also tried setting the header:

response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"

But nothing works when I use the web service to download the file. However, same method works directly in the browser [I tested by bypassing authentication in the code].

I tried using send_date, but it does not work:

File.open(document.file[:path], 'r') do |f|
send_data f.read, :type => document.file[:content_type], :filename => document.name, :disposition => 'inline'
end

As a workaround I tried redirect_to instead of send file and used a test file in the public folder and it works. Although insecure but this seems to work fine. The only problem is that the browser is now opening the document instead of downloading it.

Please help me.

Update: The problem was related to the fact that Rails now sends chunked content and the web service was expecting content length.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

扬花落满肩 2024-12-12 12:37:09

这不是 send_file 的问题。这就是 .NET Web 服务的编程方式。它期望内容长度。

发送内容时的默认行为发生了变化(Rails 2 和 Rails3 之间)。现在它是分块内容 - 因此不能有内容长度。

.NET 人员更改了代码,现在一切正常!希望这会对某人有所帮助。

It was not a problem with send_file. It was how the .NET web service was programmed. It was expecting content length.

There is a change (between Rails 2 & Rails3) in the default behaviour when sending content. Now it is chunked content - so there can not be a content length.

The .NET guy changed the code and everything is now working fine! Hope this would help somebody.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文