請原諒我是乙個頭條新聞派對,但實際上這個坑與取物關係不大它歸結為傳送 http 響應、八卦和直截了當。 為了好玩,我在自己的實踐專案中用原生的 JS fetch API 替換了 vue-resource,使用效果還是極好的,沒有像其他原生 API 那樣晦澀難懂。
在上一篇文章中,fetch 一直在門口,所以這裡只是重點,之前使用 vue-resource 和 fetch 的時候,我在 conten-type 設定上吃了很多虧,所以我做了很多功課,重要的說了三遍,post request content-type,也就是設定資料請求格式的主要方式: application x-www-form-urlencoded (大多數請求都可用:eg:。'name=denzel&age=18'Multipart form-data(檔案上傳,這次重點放在) 應用程式 json(json格式物件,例如:) text xml(現在用得很少,傳送xml格式的檔案或流,webservice請求用得比較多) 我想通過fetch非同步上傳乙個**到伺服器儲存,然後返回服務的響應位址(要求很簡單, 沒有)。所以我寫了**:
let data =new formdata();data.append('file',$("#realfile").files[0]);data.append('name','denzel'),data.append('flag','test')const option = , body:data};fetch('http://localhost:8089/analyse/imguploadservlet',option) .then(function(response)else })then(function(data))但是伺服器上列印的是這樣的錯誤訊息(幸運的是後端使用了 try-catch,否則會彈出很多錯誤,您將無法找到您):
錯誤訊息:請求被拒絕,因為沒有多部分邊界
發現很荒謬,沒有後端**在獲取資料之前,已經檢查了請求的內容型別,並且沒有錯誤,也就是說是檔案上傳的請求,沒問題,而這個上傳檔案的後端**,我之前在jsp頁面用過,沒問題,然後在Google dev-tools中檢查請求:
if (!servletfileupload.ismultipartcontent(request))dev-tools 請求資訊:
access-control-allow-methods:post, get, options, delete access-control-allow-origin:* content-length:0 content-type:text/html;charset=utf-8 date:sun, 16 jul 2017 01:51:51 gmt server:apache-coyote/1.1 request headers view source accept:*/* accept-encoding:gzip, deflate, br accept-language:zh-cn,zh;q=0.8,en;q=0.6 connection:keep-alive content-length:68172 content-type:multipart/form-data host:localhost:8089 origin:http://localhost referer:http://localhost/ user-agent:mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/59.0.3071.115 safari/537.36 request payload --webkitformboundaryj0rfrwvz56lnpj1u content-disposition: form-data; name="file"; filename="chn.png" content-type: image/png --webkitformboundaryj0rfrwvz56lnpj1u content-disposition: form-data; name="name" denzel --webkitformboundaryj0rfrwvz56lnpj1u content-disposition: form-data; name="flag" test --webkitformboundaryj0rfrwvz56lnpj1u--
這似乎沒問題,但到底是什麼,沒有多部分的邊界,只有片刻。
原來遇到這樣的問題的人並不孤單,大家都引用這樣一句話:
you should never set that header yourself. we set the header properly with the boundary. if you set that header, we won't and your server won't know what boundary to expect (since it is added to the header). remove your custom content-type header and you'll be fine.
目標語言:
您不應該自己設定請求標頭(什麼?我們將正確設定請求標頭的邊界,但如果您這樣做了,我們和您的伺服器都不會知道您的邊界是什麼(因為邊界會自動新增到請求標頭中),刪除您的自定義內容型別請求標頭設定,問題將得到解決(翻譯渣滓,雖然英語 6 級飄過,但那是六年前的事了)。
好了,知道問題出在哪裡,刪除請求頭的content-type,然後傳送,天哪,真的是啊,這怎麼可能,不就是每個http請求都應該正確設定自己的請求資料型別嗎?是不是白看了我以前的書啊,冷靜一下,別人說的沒錯,然後通過dev-tools檢查請求資訊。
accept:*/* accept-encoding:gzip, deflate, br accept-language:zh-cn,zh;q=0.8,en;q=0.6 connection:keep-alive content-length:88623 content-type:multipart/form-data; boundary=---webkitformboundaryanydwsq1ajkugocd host:localhost:8089 origin:http://localhost referer:http://localhost/ user-agent:mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/59.0.3071.115 safari/537.36 request payload --webkitformboundaryanydwsq1ajkugocd content-disposition: form-data; name="file"; filename="screenshot_2017-05-23-11-41-22-090_com.wacai365.png" content-type: image/png --webkitformboundaryanydwsq1ajkugocd content-disposition: form-data; name="name" denzel --webkitformboundaryanydwsq1ajkugocd content-disposition: form-data; name="flag" test --webkitformboundaryanydwsq1ajkugocd--
對比上面失敗的請求,我發現 content-type 後面跟著 boundary=---webkitformboundaryanydwsq1ajkugocd 這樣的火星字元字串,然後看一下傳送的資料,資料被請求的資料型別的邊界字串隔開,好像,我稍微明白一點,什麼是邊界,就是 http 請求中指定的資料交換規則。 類似於:A 向 B 傳送了乙個請求,並告訴 B,我給你寄了三個快遞員(但為了方便處理,我把它綑綁成乙個包裹),快遞單上寫明了包裹拆分的規則,所以 B 按照 A 說的規則拆分包裹。
我得出的結論是,它應該被正確設定。 當 fetch 傳送 POST 字元的請求時,當檔案沒有上傳時,不管你傳送的資料格式是 application x-www-form-urlencoded 還是 application json 格式的資料,你不設定請求頭,fetch 會預設給你新增乙個 content-type = text xml 型別的請求頭,一些第三方 jax 你可以識別你傳送的資料並自行轉換, 但 Feth 絕對不會,不,你可以試一試;當發出檔案上傳請求時,我們不知道邊界是如何定義的,因此,正如建議的那樣,我們不設定 content-type。 如果本文中的描述不正確,請指正並一起討論,畢竟您的知識有限。