Webpack运行后,XMLHttpRequest发送带参请求,后台$_POST没有数据


环境:

  打包工具: Webpack;

  整合软件包: WAMP;

  编辑器:VsCode;

 Webpack虚拟出的端口号是8080,本地Apache的端口号是80

问题重现:

JS代码,使用FormData对象作为传输数据的格式:

function postData() { var formData = new FormData(); formData.append("data", JSON.stringify({name:'xxx', age:20})); function xhrRequest(resolve, reject) {   var xhr = new XMLHttpRequest();   xhr.open('POST', _this.gRequestPhpUrl);   xhr.setRequestHeader("cache-control","no-cache"); //②   xhr.onreadystatechange = function() {   if (this.readyState === 4 && this.status === 200){     var dataResp = JSON.parse(this.responseText);     resolve(dataResp, this);   }   else {   reject('网络错误:' + this.status, this);   }   }   xhr.send(formData); } var sendReq = new Promise(xhrRequest); return sendReq; }

PHP代码,使用跨域接收他域传来的访问请求:

<?php header('Access-Control-Allow-Origin:*'); header('Access-Control-Allow-Headers: cache-control'); //① if ( !isset($_POST['data'])){ return; } file_put_contents('./rec.txt', json_encdoe($_POST['data']));   $objResp = new class{};   $objResp->data = 'this is from server';   echo json_encode($objResp); ?>

问题:

  XMLHttpRequest请求代码在Webpack虚拟的环境中发出,请求PHP文本资源。调试PHP时发现JS发起请求后,$_POST数组处于—— 一次请求数组为空、下一次请求数组有元素、再下一次请求数组又为空,这样有序的循环中。且每次请求file_get_contents("php://input", "r")中也没有值。

  奇怪的是当$_POST数组为空时前端竟然收到了正确的JSON格式消息。

问题排查:

  觉得奇怪的是前台用FormData包裹的数据,后台$_POST数组却为空,且从‘php://input’中读不到值。

 1. 怀疑JS发起请求的请求头‘Content-Type‘值不对。Server通过这个字段得到请求头的类型,然后进行解析。[1]  如果解析不对,$_POST数据将出错或没有数据。 ——》  尝试各种’Content-Type‘,没有解决这个问题;

 2. 注意到浏览器控制台有OPTIONS类型的请求,即某次请求发出,控制台出现一次OPTIONS请求,

发现该请求里没有请求数据,此时调试PHP,发现$_POST为空的情况。随即在没有手动发送请求情况下控制台自动发出一次POST请求,这时请求里包含请求数据。

 

解决方案:

  不让浏览器发送OPTIONS请求,而是只发送一次POST请求。

  查阅资料后了解OPTIONS请求是一个预检请求,xhr判断请求头里的URL路径是否能被访问到,若不能的话就返回一个CORS策略问题(

上图是注释掉①处代码会出现的问题,因为跨域时PHP需要设置能够接收包含’cache-control‘的请求头),若可以的话就会再次发送原来的POST请求。

 如果在跨域时不想要发送OPTIONS请求,需满足下列条件:[2]

1. 不要发送下列方法的请求:

  PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH

2. 除请求头自带的设置,不要手动设置除下列的其它字段:

  Accept、Accept-Language、Content-Language、Content-Type (but note the additional requirements below)、DPR、Downlink、Save-Data、Viewport-Width、Width

3.  上述2中的’Content-Type‘字段不可以设置除以下的值:

  application/x-www-form-urlencoded、multipart/form-data、text/plain

 

综上所述,只要把代码中的①和②处注释掉就可以了。

如果请求头必须带上指定其它类型字段,可以为请求头添加“Access-Control-Max-Age”字段,该字段指明访问某个跨域URL的预检请求缓存时间。设置完毕后,第一次访问某个跨域URL会发送OPTIONS预检请求,随后浏览器缓存该预检请求,在随后的缓存时间内,再次访问该URL将不会发送预检请求。

参考:

[1]    https://blog.csdn.net/qq_27845259/article/details/83106391   ——   ’Content-Type‘字段类型及简介

[2]    https://juejin.im/entry/58eaf351a22b9d0058a8e35c    ——    浅谈 AJAX 跨域请求时的 OPTIONS 方法

https://segmentfault.com/a/1190000016040998   ——   发送两次请求,其中有个是OPTIONS请求


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM