解決錯誤指定RequestHeader導致後臺接受不到FormData資料的問題
阿新 • • 發佈:2019-01-04
問題的起因是現在做的一個WEB API專案中需要以formdata的方式向後臺提交資料(包括一個JSON和一張圖片)。
之前一直是用以下程式碼傳送資料,沒出過問題。
if (window.XMLHttpRequest) { // Mozilla 瀏覽器 //新建XMLHttpRequest物件 xmlhttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE 瀏覽器 try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { } } } var fd = new FormData(); var file = document.getElementById('filebox_file_id_1'); var fileList = file.files; if (fileList.length != 0) { if (fileList[0].length / 1024 / 1024 > 20) { alert("所選圖片大小超出限制(20MB),無法上傳!"); $('#fileToUpload').filebox('setValue', ''); return; } fd.append("fileToUpload", fileList[0]); } fd.append("data",JSON.stringify(jsondata)); xmlhttp.open("POST", "../api/Company/Register", true); //規定傳送的型別,檔案在伺服器的位置,是否非同步傳送 xmlhttp.setRequestHeader("Content-Type", "multipart/form-data"); //POST方式需要的語句,形成表單 xmlhttp.send(fd);
但是後來改需求的時候做測試發現一個很奇葩的問題,就是用火狐瀏覽器提交註冊請求的時候後臺取不到資料,但IE下正常(取資料的程式碼如下)。
JObject data = JObject.Parse(HttpContext.Current.Request["data"]);
HttpFileCollection files = HttpContext.Current.Request.Files;
這就很奇怪了,因為一般來說火狐的相容性要比IE好。於是上FIDDLER抓包。
先看TextView,格式完全一致,後臺取出的InputStream也是一樣的。
火狐
-----------------------------22544859410221
Content-Disposition: form-data; name="data"
{"f_CompanyName":"9","f_CompanyCode":"9","f_CompanyLicense":"9","f_Remark":""}
-----------------------------22544859410221--
IE
-----------------------------7e1346131e0382 Content-Disposition: form-data; name="data" {"f_CompanyName":"9","f_CompanyCode":"9","f_CompanyLicense":"9","f_Remark":""} -----------------------------7e1346131e0382--
但是這個InputStream取出的字串包含了分隔符資訊,是沒法直接轉換成JObject的,用正則表示式又太麻煩,於是繼續分析。
比較一下請求頭。
火狐
POST http://localhost:2629/api/Company/Register HTTP/1.1
Host: localhost:2629
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data
Referer: http://localhost:2629/Web_Page/Register.aspx
Content-Length: 221
Cookie: CurrentUICulture=zh-CN
Connection: keep-alive
IE
POST http://localhost:2629/api/Company/Register HTTP/1.1
Accept: */*
Content-Type: multipart/form-data, multipart/form-data; boundary=---------------------------7e1346131e0382
Referer: http://localhost:2629/Web_Page/Register.aspx#
Accept-Language: zh-CN
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: localhost:2629
Content-Length: 219
Connection: Keep-Alive
Pragma: no-cache
比較一下發現一個很糾結的問題,火狐的Type裡面缺了boundary,我們知道這個boundary是分隔符,分割表單項用的。沒有指定分隔符後臺自然無法通過Current.Request獲取表單項了。
知道原因以後在回頭看程式碼,找到這麼一句:
xmlhttp.setRequestHeader("Content-Type", "multipart/form-data"); //POST方式需要的語句,形成表單
顯然就是問題所在。
分析瀏覽器生成的協議頭可以發現,IE接受了程式碼中指定的內容型別,但是又把自己的型別追加了上去(似乎不影響解析),而火狐直接把程式碼中指定的型別拿來用了,所以缺了分隔符資訊。
這次的問題提醒我,不管是網上還是之前的專案裡扒來的程式碼都不要直接用,至少要做到能看懂,知道每條語句是什麼意思,不然難免出現各種奇葩問題。