Ruby中的多部分文件上载

时间:2009-06-06 06:10:29

标签: ruby http upload mechanize multipart

我只是想用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中没有对多部分表单的本机支持,而是你必须构建一个为你编码等的类。我能找到的最有帮助的是Multipart-class by Stanislav Vitvitskiy。到目前为止,这个类看起来不错,但它不能满足我的需求,因为我不想发布文件,我也想发布正常的数据,这对他的班级是不可能的


我的最后一次尝试是使用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 个答案:

答案 0 :(得分:9)

长期问题,简短回答:我在Windows下读取图像时缺少二进制模式。

f = File.new(filename, File::RDWR)

必须是

f = File.new(filename, "rb")

答案 1 :(得分:1)

另一种方法是使用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