2012-02-14 70 views
0

我已經制作了一個servlet,它使用org.apache.commons.fileupload api上傳CSV文件,然後將其加載到MySQL表中。當從瀏覽器中的表單發佈到servlet時,這是完美的。但是,嘗試通過Tcl腳本http://www.tcl.tk/man/tcl/TclCmd/http.htm#M20發佈表單時失敗。從Tcl腳本發佈時出現MalformedStreamException

該servlet將引發以下MalformedStreamException

org.apache.commons.fileupload.MultipartStream$MalformedStreamException: 
Stream ended unexpectedly 

該servlet在Tomcat 6.0.16版本託管。

連接由Tcl腳本成功完成,因爲它接收到HTTP/1.1 200 OK響應,並且該servlet確實將一些打印語句返回給客戶端Tcl腳本。但是,嘗試讀取輸入流時失敗。

Tcl的腳本:

package require http 

proc upload { url csv } { 
    set boundary "-----WebKitFormBoundary[clock seconds][pid]" 

    set fid [open $csv r] 
    if {[catch {read $fid [file size $csv]} data]} { 
     return -code error $data 
    } 
    close $fid 

    set content {} 
    append content "--${boundary}\n" 
    append content "Content-Disposition: form-data; name=\"db\"\n\n" 
    append content "test\n" 
    append content "--${boundary}\n" 
    append content "Content-Disposition: form-data; name=\"table\"\n\n" 
    append content "testing\n" 
    append content "--${boundary}\n" 
    append content "Content-Disposition: form-data; name=\"file\"; filename=\"$csv\"\n" 
    append content "Content-Type: text/csv\n\n" 
    append content "$data\n" 
    append content "${boundary}--" 

    set headers "connection keep-alive" 
    set token [::http::geturl $url -keepalive 1 -headers $headers -query $content -type "multipart/form-data; boundary=$boundary"] 

    upvar 0 $token state 

    if {$state(http) == "HTTP/1.1 200 OK"} { 
     # no error reported in http headers 
     puts stdout $state(http) 
     puts stdout $state(body) 
     return 1 
    } else { 
     # error reported in http headers 
     puts stdout $state(http) 
     puts stdout $state(body) 
     return 0 
    } 
} 

set csv "data.csv" 
set url "http://ecat:8080/MySqlImport/MySqlImportServlet" 
set retVal [upload $url $csv] 
+0

你可以發佈你用來發布的tcl代碼嗎?很可能你沒有發佈多個請求,這是fileupload api所期望的。 – 2012-02-14 17:24:25

+0

更新爲添加tcl腳本 – Daniel 2012-02-15 11:49:13

+0

我認爲終止邊界是' - $ {boundary} - \ n'? – 2012-02-15 13:38:23

回答

0

謝謝你對這個問題的幫助,但是我發現了我的具體問題,最後這個問題很簡單。看起來好像Apache.commons.fileupload中的ServletFileUpload.parseRequest(request)方法需要行結束符爲windows格式。

正如您在問題中所看到的$ content行結尾是\n,將其更改爲\r\n可以更正此問題。

只需使用\r意味着錯誤

org.apache.commons.fileupload.MultipartStream$MalformedStreamException: 
Stream ended unexpectedly 

不再發生,但它沒有認識到在請求中不同的項目或部件。 \r\n行結尾的組合,它工作正常。

1

生成一個適當的多部分消息可以是高度加重。 Tcllib中的mime package可以提供幫助。 this page的頂部示例看起來非常相關。

0

儘管Donal Fellows最有可能是正確的,但我想用Daniel的方法指出一個(典型的)錯誤:當使用具有「字符串」概念的高級語言時到一個「字節串」—當準備被處理的數據放置在「電線」上時,人們會特別小心。

在這種情況下,「wire」是HTTP協議,因此準備的數據應該最有可能經歷類似[encoding convertto utf-8 ...]之類的事情,這取決於意圖。 (順便說一下,Tcl對二進​​制字符串有相當廣泛的支持,以便它們可以被附加到,連接等,而不會丟失它們的屬性binary。)

可以推薦的下一件事是習慣於網絡嗅探器(或特定的HTTP嗅探器)。一個很好的跨平臺解決方案是Wireshark,在Windows平臺上有Network Monitor(通用嗅探器)和Fiddler(HTTP專用)。這個想法是首先捕捉並研究瀏覽器執行的「參考」會話,然後捕獲並分析程序執行的行爲不當行爲。因此,您只需比較會話並查看生成的流量在HTTP有效負載方面的差異。