解决错误指定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接受了代码中指定的内容类型,但是又把自己的类型追加了上去(似乎不影响解析),而火狐直接把代码中指定的类型拿来用了,所以缺了分隔符信息。

这次的问题提醒我,不管是网上还是之前的项目里扒来的代码都不要直接用,至少要做到能看懂,知道每条语句是什么意思,不然难免出现各种奇葩问题。

你可能感兴趣的:(解决错误指定RequestHeader导致后台接受不到FormData数据的问题)