使用JSON与Sinatra发布POST错误

时间:2012-12-24 23:49:08

标签: ruby json post curl sinatra

我正在学习Ruby + Sinatra,并发现了一篇很好的帖子here,其中讨论了如何上传文件。

post '/upload/:filename' do
  userdir = "./upload"
  FileUtils.mkdir_p(userdir) unless File.exists?(userdir)
  filename = File.join(userdir, params[:filename])
  datafile = params[:data]
  File.open(filename, 'wb') do |file|
    file.write(datafile[:tempfile].read)
  end
end

我可以使用以下cURL命令上传文件。

curl -v -F "data=@/Users/me/Desktop/test.pdf"  http://localhost:4567/upload/test.pdf

但现在我决定使用JSON来处理所有传入/传出响应。我试过这个,但它似乎没有用。

curl -i -X POST -H Accept:application/json -H Content-Type:application/json -d '{file:{filename:"test.pdf",md5sum:"ab3d2f"}}'  --data-binary @/Users/me/Desktop/test.pdf 'http://localhost:4567/upload/test.pdf'

我也收到了这样的错误:

NoMethodError at /upload/test.pdf
undefined method `get' for #<WebTest:0x101374dd8>
file: web.rb location: POST /upload/:filename line: 48

我现在该怎么办?

编辑:

第48行是file.write(datafile[:tempfile].read

请帮忙!

3 个答案:

答案 0 :(得分:2)

我不确定你期待你的第二个curl命令做什么,但我很确定它没有做你想要的。如果您要提供多个--data-d个参数,则它们的值将连接在一起,由&分隔。

例如,如果您有一个内容为test.txt的文件This is a test.,并且您的请求是这样的:

curl -i -X POST -H Accept:application/json -H Content-Type:application/json \
    -d '{file:{filename:"test.txt",md5sum:"ab3d2f"}}'                  \
    --data-binary @test.txt 'http://localhost:4567/upload/test.txt'

这是请求的样子:

POST /upload/test.txt HTTP/1.1
User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
Host: localhost:4567
Accept:application/json
Content-Type:application/json
Content-Length: 61

{file:{filename:"test.txt",md5sum:"ab3d2f"}}&This is a test.

请求正文无效JSON。它不是有效的URL编码表单数据或多部分表单数据。

如何将JSON请求与文件上传相结合并不明显。以下是一些选项:

  • 只需使用multipart/form-data即可。也就是说,使用您的Ruby代码和-F选项来完成您现在正在做的事情。
  • multipart/form-data与JSON的一部分用于元数据,将其他部分与原始上传文件一起使用。
  • 通过base64编码将文件嵌入到JSON中。
  • 执行某种双请求工作流,首先将元数据发布为JSON,然后在POST正文中上传文件。

我可能会选择第一个选项,因为它得到了广泛的支持。

答案 1 :(得分:1)

好像你的Ruby代码坏了;你忘记了end

post '/upload/:filename' do
  userdir = "./upload"
  FileUtils.mkdir_p(userdir) unless File.exists?(userdir)
  filename = File.join(userdir, params[:filename])
  datafile = params[:data]
  File.open(filename, 'wb') do |file|
    file.write(datafile[:tempfile].read)
  end
end

答案 2 :(得分:0)

现在我可以使用以下curl命令使用JSON:

curl -v -F 'json=[ {"filename": "@/Users/me/Desktop/test.pdf", "md5sum": "1496f9b6f42b7ed8260eadeb158c33f4", type": "generic"}, {"filename": "@/Users/me/Desktop/test2.pdf", "md5sum": "1496f9b6f42b7ed8260eadeb158c33f4", type": "generic"} ]' http://localhost:4567/upload

但是,由于我不使用-F 'file=@/Users/me/Desktop/test.pdf'来发布我的文件,如何使用JSON对象在服务器端检索文件?

以下不再有效。

tempfile = params[:file][:tempfile]
filename = params[:file][:filename]
dest = "#{userdir}/#{filename}"
FileUtils.cp(tempfile.path, dest) if not File.exists?(dest)