AJAX提交FormData至PHP时$_POST获原始边界数据而非字段数组问题
问题
我通过AJAX用FormData向PHP页面提交包含Base64编码字符串的表单字段和普通文本字段时遇到了麻烦:
- 如果省略请求头或者设置
multipart/form-data,Firefox调试器没办法显示请求/响应内容; - 只有设置
xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8")的时候能拿到结果,但PHP里的$_POST返回的是原始的表单字段内容,不是可以直接便捷访问的数组。
相关JS代码:
var thisData = new FormData(thisForm); xmlHttp.open("POST", thisURL+"&rndnbr="+numRand, true); // 无效! // xmlHttp.setRequestHeader("Content-type", "multipart/form-data; charset=UTF-8"); // 移除Content-type也无效! xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8"); xmlHttp.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xmlHttp.send(thisData);
PHP中打印$_POST的结果:
array (size=1) '-----------------------------3647481290304128341773697748 Content-Disposition:_form-data;_name' => string '"aaas_file_test" test -----------------------------3647481290304128341773697748 Content-Disposition: form-data; name="testfield1" test1 -----------------------------3647481290304128341773697748 Content-Disposition: form-data; name="testfield2" test2 -----------------------------3647481290304128341773697748 Content-Disposition: form-data; name="testfield3" test3 -----------------------------3647481290304128341773697748 Content-Disposition: form-data; name="file_base64" UEsDBBQABgAIAAAAIQBm4xtW2w -----------------------------3647481290304128341773697748-- ' (length=565)
请问怎么让PHP获取规整的表单字段数组,而不是这种原始的POST数据?
解决方法
嘿,这个问题其实很好解决,根源在于你对FormData和请求头的搭配理解有点偏差:
核心原因
当你用XMLHttpRequest.send(FormData)时,浏览器会自动按照multipart/form-data格式编码数据,并且自动设置正确的Content-Type请求头(包括生成唯一的分隔符)。但你手动设置了application/x-www-form-urlencoded头,这就导致PHP收到的请求体格式和头信息不匹配,自然无法正确解析成$_POST数组,只能拿到原始的字符串。
下面给你两个靠谱的方案:
方案1:用FormData默认的multipart/form-data格式(推荐)
你完全不需要手动设置multipart/form-data请求头,浏览器会帮你搞定。另外,Firefox调试器是能查看multipart/form-data请求内容的——你只需要在「网络」面板找到对应的请求,切换到「表单数据」标签页,就能看到解析后的各个字段了,之前可能是没找对地方~
修改后的JS代码:
var thisData = new FormData(thisForm); // 把随机数参数加到FormData里,别拼在URL后面(虽然拼URL也能工作,但POST参数放请求体更规范) thisData.append('rndnbr', numRand); xmlHttp.open("POST", thisURL, true); // 只保留AJAX标识头,移除手动设置的Content-type! xmlHttp.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xmlHttp.send(thisData);
这样处理后,PHP里就能直接通过$_POST['testfield1']、$_POST['file_base64']这类方式访问字段,$_POST就是你想要的规整数组了。
方案2:转为application/x-www-form-urlencoded格式提交
如果你确实需要用application/x-www-form-urlencoded格式,那不能直接把FormData传给send(),得先把它转换成符合格式的字符串。可以用URLSearchParams来轻松完成这个转换:
var thisData = new FormData(thisForm); thisData.append('rndnbr', numRand); // 把FormData转成URL编码的字符串 var encodedData = new URLSearchParams(thisData).toString(); xmlHttp.open("POST", thisURL, true); xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8"); xmlHttp.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xmlHttp.send(encodedData);
这个方案下,PHP的$_POST同样能拿到规整的数组,同时Firefox调试器也能正常显示请求内容。
内容的提问来源于stack exchange,提问作者user1594257

