React Native Expo中POST请求失效,GET请求正常的问题排查
问题:POST请求服务器无法接收数据,GET请求正常
我尝试用POST方法实现登录功能,但服务器接收不到请求中的数据。Postman测试时数据能成功发送,先后试过Axios和Fetch API两种方式都无效,但GET请求可以正常工作。
相关代码与信息
请求头配置代码
import axios from 'axios'; import React from 'react'; import { appPackageName, ApiKey, ApiServer } from '@/constants'; import { MyObject } from '@/interface'; import { Platform } from 'react-native'; const headers: MyObject = { 'Content-Type': 'application/json', }; if (Platform.OS !== 'web') { headers['APP_PACKAGE_NAME'] = appPackageName; }
Axios请求代码
export async function postData(relativeUrl: string, requestData: MyObject): Promise<MyObject> { try { headers['Authorization'] = `Bearer ${ApiKey}`; console.log({ ...requestData }); const response = await axios.post( `${ApiServer}/${relativeUrl}`, { ...requestData }, // 试过JSON.stringify(requestData)、不展开、不序列化的情况都不行 { headers: headers, withCredentials: true, } ); return response.data; } catch (error) { console.error('Error fetching data:', error); throw new Error('Failed to fetch data'); } }
Fetch请求代码
export async function postData(relativeUrl: string, requestData: MyObject): Promise<MyObject> { try { headers['Authorization'] = `Bearer ${ApiKey}`; console.log({ ...requestData }); const response = await fetch(`${ApiServer}/${relativeUrl}`, { method: 'POST', headers: headers, body: JSON.stringify(requestData), }); console.log(response); const data = await response.json(); return data; } catch (error) { console.error('Error fetching data:', error); throw new Error('Failed to fetch data'); } }
GET请求代码
export async function getData(relativeUrl: string, requestData: MyObject): Promise<MyObject> { try { const response = await axios.get( `${ApiServer}/${relativeUrl}`, { headers: headers, params: requestData, } ); console.log(response.data); return response.data; } catch (error) { console.error('Error fetching data:', error); throw new Error('Failed to fetch data'); } }
浏览器请求头
POST /public/auth/login HTTP/1.1 Host: localhost:9016 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0 Accept: application/json, text/plain, */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br, zstd Content-Type: application/json Authorization: Bearer TOKEN_CODE Content-Length: 97 Origin: http://localhost:8081 Connection: keep-alive Referer: http://localhost:8081/ Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-site Priority: u=0
Postman请求头
Cookie: PHPSESSID=vcug376r85rus7fj3aep0pivmm Cache-Control: no-cache Postman-Token: <calculated when request is sent> Content-Type: multipart/form-data; boundary=<calculated when request is sent> Content-Length: <calculated when request is sent> Host: <calculated when request is sent> User-Agent: PostmanRuntime/7.39.1 Accept: */* Accept-Encoding: gzip, deflate, br Connection: keep-alive Authorization: Bearer TOKEN_CODE Content-Type: application/json
PHP CORS校验代码
/** * Set up headers that handle API requests */ require_once $_SERVER['DOCUMENT_ROOT'].'/src/env-var.php'; $headers = getallheaders(); // Get the request's Origin header $origin = $_SERVER['HTTP_ORIGIN'] ?? ''; // Handle preflight requests if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); header("Access-Control-Allow-Headers: Authorization, Content-Type, HTTP_X_APP_PACKAGE_NAME"); if (isset($headers['Authorization']) || isset($headers['Credentials'])) { header('Access-Control-Allow-Credentials: true'); } header('Access-Control-Max-Age: 86400'); // Cache for 1 day header('Content-Type: application/json'); exit(0); } // Set general CORS headers header('Content-Type: application/json'); if(preg_match('/development/',ENV)){ header("Access-Control-Allow-Origin: *"); } else if (isset($_SERVER['HTTP_X_APP_PACKAGE_NAME']) && in_array($_SERVER['APP_PACKAGE_NAME'], $allowedApps)) header("Access-Control-Allow-Origin: *"); elseif (isset($_SERVER['HTTP_ORIGIN']) && in_array($origin, $allowedOrigins)) header("Access-Control-Allow-Origin: $origin"); else { http_response_code(401); echo json_encode(['error' => 'Unauthorized Access']); exit; } // Allow credentials if the request includes Authorization or Credentials header if (isset($headers['Authorization']) || isset($headers['Credentials'])) { header('Access-Control-Allow-Credentials: true'); } // Allow specified methods header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // Allow specific headers header("Access-Control-Allow-Headers: Authorization, Content-Type, X-Custom-Header"); // Cache for 1 day header('Access-Control-Max-Age: 86400');
解决方案
1. 修复服务器端JSON格式数据的接收逻辑
前端发送的是application/json格式请求体,但PHP默认仅会解析application/x-www-form-urlencoded或multipart/form-data格式的数据到$_POST数组。如果服务器端仍用$_POST获取数据,自然拿不到JSON内容。
修改服务器端获取POST数据的代码:
// 替换原有的POST数据获取逻辑 $postData = json_decode(file_get_contents('php://input'), true); // 之后用$postData访问字段,比如$postData['username']
2. 统一请求格式(可选)
Postman请求头同时存在两个Content-Type,实际测试时可能发送的是form-data格式,因此服务器用$_POST能拿到数据。如果要改为前端发送form-data,可调整Axios代码:
import FormData from 'form-data'; // React Native需额外安装form-data包 export async function postData(relativeUrl: string, requestData: MyObject): Promise<MyObject> { try { headers['Authorization'] = `Bearer ${ApiKey}`; delete headers['Content-Type']; // 让Axios自动生成form-data的Content-Type和boundary const formData = new FormData(); Object.keys(requestData).forEach(key => { formData.append(key, requestData[key]); }); const response = await axios.post( `${ApiServer}/${relativeUrl}`, formData, { headers: headers, withCredentials: true, } ); return response.data; } catch (error) { console.error('Error fetching data:', error); throw new Error('Failed to fetch data'); } }
3. 修正PHP CORS代码的变量错误
原CORS代码中存在变量名错误:
// 原错误代码 else if (isset($_SERVER['HTTP_X_APP_PACKAGE_NAME']) && in_array($_SERVER['APP_PACKAGE_NAME'], $allowedApps))
自定义请求头在PHP的$_SERVER中会被添加HTTP_前缀并转为大写,因此$_SERVER['APP_PACKAGE_NAME']应改为$_SERVER['HTTP_APP_PACKAGE_NAME'],修改后:
else if (isset($_SERVER['HTTP_APP_PACKAGE_NAME']) && in_array($_SERVER['HTTP_APP_PACKAGE_NAME'], $allowedApps))
另外,OPTIONS请求中允许的头是HTTP_X_APP_PACKAGE_NAME,但前端发送的是APP_PACKAGE_NAME,需统一两者:要么前端改为发送X-APP-PACKAGE-NAME,要么OPTIONS中的允许头改为APP_PACKAGE_NAME,避免预请求失败。
内容的提问来源于stack exchange,提问作者Amit Creation
相关产品推荐
相关产品推荐

