2012-12-24 71 views
1

我學習Ruby +西納特拉,發現好的帖子here其中談到如何上傳文件。POST錯誤與西納特拉與JSON

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 "[email protected]/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

請幫幫忙!

+1

您需要調試。首先,我會確定哪一行是第48行。 – akonsu

+0

根據Sinatra的說法,它絕對是如何爲POST使用「路由」的。除非我錯過這裏的東西。 – xbeta

+0

爲什麼我會關心「GET」,因爲我只需要構建一個POST方法。並且只會使用POST方法。 – xbeta

回答

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體。

我可能會去第一個選項,因爲它是如此廣泛的支持。

+0

謝謝!這是一個有用的答案! 我正在使用第一個選項,但它只支持上傳1個二進制文件。如果我也想同時發佈文件和JSON內容(包括該文件的MD5sum),我該如何發佈它? 我還沒有看到一個在線的例子。 – xbeta

+1

您可以爲其他數據設置「表單域」。 'curl -F'md5sum = ab3d2f' -F'[email protected]'http:// ...'然後在Ruby中用'params [:md5sum]'來訪問它。你也可以用這種方式發佈一個JSON對象。 'curl -F'json = {file:{filename:「test.txt」,md5sum:「ab3d2f」}}'...'然後用Ruby解碼。 – Miikka

+0

謝謝!但是,如何使用JSON對象方式傳輸嵌入文件? – xbeta

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 
+0

我確實有過,但沒有正確複製和粘貼。仍然無法使上述錯誤得到運行。 – xbeta

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 '[email protected]/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) 
+0

如果您沒有使用'-F'[email protected]',則該文件不包含在請求中,這不能完成。 – Miikka

+0

我在考慮在POST請求中傳遞多個文件。我們還可以通過其他方式做到這一點? – xbeta

+0

@xbeta答案是答案,問題是問題。這應該是對問題的更新,或者這裏的額外信息應該是一個新問題。此外,「現在我可以得到它的工作」是沒有意義的。嘗試'警告params.keys.inspect',看看你現在收到了什麼,因爲它看起來像你正在發送一個哈希數組,現在通過按鍵訪問將無法工作。 – iain