如何使用GRAPE API允许二进制文件下载

10

我想在Ruby的Grape API中允许下载二进制文件(.p12文件),以下是我的尝试:

get '/download_file' do
  pkcs12 = generate_pkcsfile 
  content_type('application/octet-stream')
  body(pkcs12.der)
end

使用ActionController的等效代码为

begin
  pkcs12 = generate_pkcsfile
  send_data(pkcs12.der,
            :filename => 'filename.p12')
end

问题在于使用API下载的文件似乎是一个带有'\ufffd'前缀的文本文件,而使用浏览器下载的文件则是二进制文件。我该如何使用GRAPE API框架来实现通过ActionController的send_data下载与浏览器下载相同的文件。


与使用ActionController的请求输出相比,您是否看到返回的Content-Type HTTP标头有所不同?它们是否具有不同的字符集? - Stuart M
当你在问题中比较API和浏览器时,是不是实际上指的是“API客户端加上API路由”与“浏览器加上ActionController路由”?有四种可能的组合,并且不清楚你遇到的问题是哪一种——根据你的描述,问题实际上可能在于你的测试API客户端。 - Neil Slater
好的。为了测试葡萄API,我使用curl/wget作为客户端和/download_file作为端点。为了测试ActionController,我使用火狐浏览器和/keys作为端点。换句话说,这两个端点是不同的,但我希望在这两个端点上获得相同的行为。我检查了这两个头文件。浏览器/keys响应头中的内容类型为'text/html; charset=utf-8',而葡萄响应头中的内容类型为'application/octet-stream'。然而,将葡萄代码切换为返回'text/html; charset=utf-8'并没有改变响应体。 - boboverflow
我无法使用curl复制该故障(即,我的答案中的代码在使用curl时按预期工作)。然而,我正在直接在rackup上挂载Grape,并想知道是否有一些Rails中间件会对您产生干扰。您是否尝试过直接托管Grape服务,而不是使用Rails来排除这种可能性? - Neil Slater
2个回答

19

有一些问题#412#418已经在grape的GitHub页面上报告。

这些问题涉及返回二进制文件和覆盖内容类型。

要返回二进制格式,可以这样做:

get '/download_file' do
    content_type "application/octet-stream"
    header['Content-Disposition'] = "attachment; filename=yourfilename"
    env['api.format'] = :binary
    File.open(your_file_path).read
end

你可能也想使用 File.binread(your_file_path) 来确保安全。 - Kevin Hutchinson

1

我认为你的葡萄代码很好,我使用浏览器和Mac HTTP工具(称为GraphicalHTTPClient)测试了它的一个变体,成功地从磁盘加载了一个二进制文件并使用几乎与你相同的代码传输了MIME类型为'application/octet-stream'的文件:

  get :download do
    data = File.open('binary_data').read
    content_type 'application/octet-stream'
    body data
  end

我认为你的问题可能与API客户端和/或字符编码有关(正如Stuart M所建议的)。虽然从我们迄今的讨论中我想到的另一个可能性是,一些Rack中间件被错误地触发,并修改了Grape的输出。

感谢大家的回复。我尝试将葡萄端点切换为返回与send_data相同的字符编码,但是我没有看到响应正文有任何变化。我考虑将ActionController和Grape端点代码都切换为返回Base64编码字符串,以确保两种用例的行为完全一致。 - boboverflow
我怀疑这里需要一个 force_encoding 来处理数据。如果你能在一个简单的Grape应用程序中重现这个问题,请在Grape邮件列表上提出来。 - dB.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接