使用rest-api-sdk-php 1.13.0对接PayPal时遇400 MALFORMED_REQUEST错误
嘿,我刚帮几个朋友排查过类似的PayPal集成问题,这个400 MALFORMED_REQUEST错误其实大多是请求JSON不符合PayPal API的规范——哪怕是一个字段名拼写错、格式不对或者必填项缺失都会触发它。结合你用的是rest-api-sdk-php 1.13.0,给你几个针对性的排查方向:
1. 检查请求对象的必填字段
PayPal创建payment的请求有几个绝对不能少的核心字段,很多新手容易在这里踩坑:
intent:必须是sale(即时付款)、authorize(预授权)或order(订单)三者之一,别拼写错误payer.payment_method:对于REST API,这里必须填paypal(不能是其他自定义值)transactions数组:每个transaction里必须包含amount,而amount里必须有total(字符串类型,比如"10.00",不能直接传数字)和currency(PayPal支持的大写代码,比如USD、EUR)redirect_urls:必须包含return_url和cancel_url,这两个是用户完成/取消支付后跳转的地址,绝对不能漏
2. 验证SDK请求构建代码
因为你用的是官方SDK,一定要用SDK提供的对象来构建请求,别手动拼接JSON(很容易出错)。给你一个标准的示例片段,你可以对比自己的代码:
// 初始化API上下文 $apiContext = new ApiContext( new OAuthTokenCredential( '你的沙箱客户端ID', '你的沙箱密钥' ) ); $apiContext->setConfig([ 'mode' => 'sandbox', // 注意是sandbox,别写成test或者production 'http.ConnectionTimeOut' => 30, ]); // 构建Payment对象 $payment = new Payment(); $payment->setIntent('sale'); // 设置付款方 $payer = new Payer(); $payer->setPaymentMethod('paypal'); $payment->setPayer($payer); // 设置金额 $amount = new Amount(); $amount->setCurrency('USD'); $amount->setTotal('10.00'); // 必须是字符串,保留两位小数 // 设置交易信息 $transaction = new Transaction(); $transaction->setAmount($amount); $transaction->setDescription('你的商品描述'); $payment->setTransactions([$transaction]); // 设置跳转地址(必填!) $redirectUrls = new RedirectUrls(); $redirectUrls->setReturnUrl('https://你的网站域名/paypal-success'); $redirectUrls->setCancelUrl('https://你的网站域名/paypal-cancel'); $payment->setRedirectUrls($redirectUrls); // 发起请求 try { $payment->create($apiContext); // 获取跳转链接 $approvalUrl = $payment->getApprovalLink(); header("Location: $approvalUrl"); } catch (PayPalException $ex) { // 捕获异常,查看错误详情 echo $ex->getMessage(); }
对比你的代码,看看有没有漏了RedirectUrls,或者字段赋值错误(比如把setTotal的参数传成了数字10而不是字符串"10.00")。
3. 开启SDK日志,查看实际发送的JSON
这是最直接的排查方法——让SDK输出实际发送给PayPal的请求内容,就能一眼看到哪里格式不对。在初始化apiContext的时候添加日志配置:
$apiContext->setConfig([ 'mode' => 'sandbox', 'http.ConnectionTimeOut' => 30, 'log.LogEnabled' => true, 'log.FileName' => './PayPal.log', // 日志文件路径,确保服务器有写入权限 'log.LogLevel' => 'DEBUG' // 会输出详细的请求和响应内容 ]);
发起支付请求后,打开PayPal.log,找到发送的JSON请求体,和PayPal官方文档里的创建Payment请求示例对比,就能快速定位问题——比如某个字段名拼写成curreny而不是currency,或者total没有保留两位小数。
4. 检查SDK版本和API兼容性
rest-api-sdk-php 1.13.0是比较旧的版本了,PayPal的API可能有一些字段变化。你可以在apiContext里明确指定API版本,确保和SDK兼容:
$apiContext->setConfig([ 'mode' => 'sandbox', 'http.ConnectionTimeOut' => 30, 'api.version' => 'v1' ]);
5. 验证沙箱账号和密钥
虽然错误提示是请求格式问题,但也顺便确认下:你的客户端ID和密钥是沙箱环境的(不是生产环境的),而且沙箱账号处于正常状态(没有被限制)。
如果按照上面的步骤排查后还是有问题,把日志里的请求JSON内容(记得打码敏感信息)贴出来,就能更精准地定位问题啦!
内容的提问来源于stack exchange,提问作者André Castro

