PhonePe支付API跨域问题求助:本地及线上环境请求失败
问题描述
调用PhonePe预生产环境支付API(接口地址:https://api-preprod.phonepe.com/apis/merchant-simulator/pg/v1/pay)时遇到以下问题:
- 请求体为Base64编码的payload,请求头携带Sha256加密的
x-verify参数 - 在PhonePe官网提供的Postman示例中调用完全正常,可获取交易初始化响应
- 但在本地
localhost环境和正式网站上发起请求时,均触发CORS拦截,报错信息:
Access to fetch at 'https://api-preprod.phonepe.com/apis/merchant-simulator/pg/v1/pay' from origin 'https://www.wearmiho.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
尝试添加mode: "no-cors"参数后,请求依然失败。目前已排查两个方向:
- 怀疑需在PhonePe平台预注册域名,但PhonePe团队明确表示测试凭证支持任意URL(本地或线上网站)
- 代码严格遵循PhonePe开发者文档中的Postman示例编写,暂未发现明显错误
核心原因
浏览器同源策略会拦截前端直接发起的跨域请求,PhonePe预生产API服务器未配置允许前端跨域的响应头(如Access-Control-Allow-Origin),导致预飞(OPTIONS)请求失败。添加no-cors仅能让请求不报错,但会返回不透明响应,无法获取交易初始化数据,无法满足业务需求。
可行解决方案
1. 搭建后端代理服务(推荐)
前端不直接请求PhonePe API,改为请求自身后端接口,由后端转发请求到PhonePe API(后端请求不受浏览器同源策略限制):
- 后端在响应中添加允许前端域名的CORS头(如
Access-Control-Allow-Origin: https://www.wearmiho.com或*) - 前端请求后端代理接口,获取返回的交易数据
示例Node.js代理代码(基于Express):
const express = require('express'); const axios = require('axios'); const cors = require('cors'); const app = express(); // 配置允许的前端域名 app.use(cors({ origin: ['http://localhost:3000', 'https://www.wearmiho.com'] })); app.use(express.json()); // 代理接口 app.post('/api/phonepe/pay', async (req, res) => { try { const phonePeResponse = await axios.post( 'https://api-preprod.phonepe.com/apis/merchant-simulator/pg/v1/pay', req.body, { headers: req.headers } ); res.send(phonePeResponse.data); } catch (error) { res.status(error.response?.status || 500).send(error.response?.data || '代理请求失败'); } }); app.listen(4000, () => console.log('代理服务运行在4000端口'));
前端修改请求地址为代理接口:
fetch('/api/phonepe/pay', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-verify': '你的Sha256加密值' }, body: JSON.stringify({ base64Payload: '你的Base64编码payload' }) }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.error(err));
2. 验证请求参数细节
即使代码与Postman一致,仍需核对以下内容:
- 确认
x-verify参数生成逻辑:Sha256加密内容是否包含payload、salt等必要信息,加密后是否拼接了###{saltIndex}后缀 - 检查Base64编码的payload是否无额外空格、换行符
- 确认请求头
Content-Type符合PhonePe要求(通常为application/json)
3. 再次确认PhonePe平台配置
尽管对方表示测试凭证支持任意域名,仍可向PhonePe团队确认:
- 预生产环境API是否开启前端跨域支持
- 是否存在隐藏的域名白名单配置需手动添加
- 测试凭证权限是否允许发起前端跨域请求
内容的提问来源于stack exchange,提问作者ProXiMa Akash

