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

这会在服务器上产生一个完全可以垃圾的文件,看起来到处乱七八糟:

替代文字 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,如果发送正确,它会发回调试请求,我总是会得到这个:

使用 101 字节有效负载发布 http://rest-test.heroku.com/,
内容类型 application/x-www-form-urlencoded
{
    "pict" => "#<文件:0x30d30c4>",
    "用户名" => "s1kx",
    "pict_to" => "0",
    “功能”=>“图片2”,
    "pict_type" => "0",
    “密码” => “密码”
}

这清楚地表明它不是multipart/form-data用作 content-type 而是用作 standard application/x-www-form-urlencoded,尽管它肯定认为那pict是一个文件。


如何在不实现整个编码和数据对齐的情况下将 Ruby 中的文件上传到多部分表单?

4

2 回答 2

9

长问题,简短回答:我错过了在 Windows 下读取图像的二进制模式。

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

必须是

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

于 2009-06-06T15:44:43.503 回答
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
于 2011-02-18T21:04:28.623 回答