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