Ruby中的多部分文件上传

7
我想要使用POST方法将图片上传到服务器。虽然这个任务听起来很简单,但在Ruby中似乎没有简单的解决方案。
在我的应用程序中,我大多数情况下都使用WWW::Mechanize,所以我也想在这里使用它,并有以下源代码:
f = File.new(filename, File::RDWR)
reply = agent.post(
    'http://rest-test.heroku.com',
    {
         :pict       =>  f,
         :function   =>  'picture2',
         :username   =>  @username,
         :password   =>  @password,
         :pict_to    =>  0,
         :pict_type  =>  0
    }
)
f.close

这导致服务器上的文件完全无法使用,看起来乱七八糟:

alt text http://imagehub.org/f/1tk8/garbage.png

我的下一步是将WWW::Mechanize降级到版本0.8.5。这个方法有效,直到我尝试运行它时出现了错误,像“在hpricot_scan.so中找不到模块”。使用Dependency Walker工具,我发现hpricot_scan.so需要msvcrt-ruby18.dll。然而,即使我将该.dll放入Ruby/bin文件夹中,它也会给我一个空的错误框,从那里我无法进一步调试。所以问题在于,Mechanize 0.8.5依赖于Hpricot而不是Nokogiri(后者运行得非常流畅)。
下一个想法是使用不同的 gem,所以我尝试使用 Net::HTTP。经过简短的调查,我发现 Net::HTTP 没有原生支持多部分表单,而是必须构建一个类来为您进行编码等操作。我能找到的最有帮助的是 Stanislav Vitvitskiy 的 Multipart-class。这个类目前看起来很好,但它不能做我需要的事情,因为我不仅想要发布文件,还想发布普通数据,而这在他的类中是不可能的。

我的最后一次尝试是使用RestClient。这看起来很有前途,因为有上传文件的示例。但我无法将其作为多部分表单进行发布。

f = File.new(filename, File::RDWR)
reply = RestClient.post(
    'http://rest-test.heroku.com',
    :pict       =>  f,
    :function   =>  'picture2',
    :username   =>  @username,
    :password   =>  @password,
    :pict_to    =>  0,
    :pict_type  =>  0
)
f.close

我正在使用 http://rest-test.heroku.com,它会在请求正确发送时将其发送回来以进行调试,但我总是收到以下响应:
POST http://rest-test.heroku.com/ with a 101 byte payload,
content type application/x-www-form-urlencoded
{
    "pict" => "#<File:0x30d30c4>",
    "username" => "s1kx",
    "pict_to" => "0",
    "function" => "picture2",
    "pict_type" => "0",
    "password" => "password"
}
这清楚地表明它不使用 multipart/form-data 作为内容类型,而是使用标准的 application/x-www-form-urlencoded,尽管它确实看到 pict 是一个文件。
如何在Ruby中上传文件到多部分表单而不必自己实现整个编码和数据对齐过程?
2个回答

9
长话短说:在Windows下读取图像时,我缺少了二进制模式。
原来的代码: f = File.new(filename, File::RDWR) 现在需要修改成: f = File.new(filename, "rb")

2

另一种方法是使用Bash和Curl。当我想测试多个文件上传时,我使用了这种方法。

bash_command = 'curl -v -F "file=@texas.png,texas_reversed.png"                         
http://localhost:9292/fog_upload/upload'
command_result = `#{bash_command}` # the backticks are important <br/>
puts command_result

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