1. 程式人生 > >解決錯誤指定RequestHeader導致後臺接受不到FormData資料的問題

解決錯誤指定RequestHeader導致後臺接受不到FormData資料的問題

問題的起因是現在做的一個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接受了程式碼中指定的內容型別,但是又把自己的型別追加了上去(似乎不影響解析),而火狐直接把程式碼中指定的型別拿來用了,所以缺了分隔符資訊。

這次的問題提醒我,不管是網上還是之前的專案裡扒來的程式碼都不要直接用,至少要做到能看懂,知道每條語句是什麼意思,不然難免出現各種奇葩問題。