Laravel集成PayPal v2 SDK支付失败问题求助
PayPal v2 SDK 集成 Laravel 问题排查与解决
1. 纠正 SDK 依赖包
你安装的 paypal/paypal-payouts-sdk 是用于**批量付款(Payouts)**的包,不适合普通支付订单场景。正确的 PayPal v2 支付 SDK 是 paypal/paypal-checkout-sdk,执行以下操作替换:
# 卸载错误包 composer remove paypal/paypal-payouts-sdk # 安装正确的支付 SDK composer require paypal/paypal-checkout-sdk
2. 解决 net::ERR_CONNECTION_TIMED_OUT 问题
- 确认服务器/本地环境可访问 PayPal 沙盒域名(
api-m.sandbox.paypal.com),排查防火墙、代理或 VPN 限制。 - 在 Laravel
.env文件中正确配置沙盒凭据:
PAYPAL_MODE=sandbox PAYPAL_CLIENT_ID=你的沙盒客户端ID PAYPAL_CLIENT_SECRET=你的沙盒密钥
3. 修复 Create_order_error 与 JSON 解析错误
这类错误(Unexpected token '<')通常是后端创建订单的接口返回了HTML 错误页面(比如 Laravel 异常页面),而非预期的 JSON 响应。排查与修复步骤:
- 确保后端接口捕获异常并返回 JSON 格式错误信息,示例控制器代码:
<?php namespace App\Http\Controllers; use PayPalCheckoutSdk\Core\PayPalHttpClient; use PayPalCheckoutSdk\Core\SandboxEnvironment; use PayPalCheckoutSdk\Orders\OrdersCreateRequest; use Illuminate\Http\Request; class PayPalController extends Controller { public function createOrder() { $environment = new SandboxEnvironment(env('PAYPAL_CLIENT_ID'), env('PAYPAL_CLIENT_SECRET')); $client = new PayPalHttpClient($environment); $request = new OrdersCreateRequest(); $request->prefer('return=representation'); $request->body = [ "intent" => "CAPTURE", "purchase_units" => [[ "amount" => [ "currency_code" => "USD", "value" => "10.00" ] ]] ]; try { $response = $client->execute($request); return response()->json(['id' => $response->result->id]); } catch (\Exception $e) { return response()->json(['error' => $e->getMessage()], 500); } } }
- 前端 PayPal 按钮代码示例(确保调用正确后端接口,带 CSRF 令牌):
<script src="https://www.paypal.com/sdk/js?client-id=你的沙盒客户端ID¤cy=USD"></script> <div id="paypal-button-container"></div> <script> paypal.Buttons({ createOrder: function(data, actions) { return fetch('/api/paypal/create-order', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content } }).then(function(response) { if (!response.ok) throw new Error('请求失败'); return response.json(); }).then(function(orderData) { return orderData.id; }); }, onApprove: function(data, actions) { return actions.order.capture().then(function(details) { alert('交易完成:' + details.payer.name.given_name); }); }, onError: function(err) { console.error('PayPal 错误:', err); } }).render('#paypal-button-container'); </script>
4. 修复 Guzzle 400 Bad Request 错误
400 错误(INVALID_REQUEST)通常是请求格式或参数不符合 PayPal v2 规范,正确的 Guzzle 请求示例:
use GuzzleHttp\Client; $client = new Client(); // 第一步:获取访问令牌 $tokenResponse = $client->post('https://api-m.sandbox.paypal.com/v1/oauth2/token', [ 'auth' => [env('PAYPAL_CLIENT_ID'), env('PAYPAL_CLIENT_SECRET')], 'form_params' => ['grant_type' => 'client_credentials'] ]); $tokenData = json_decode($tokenResponse->getBody(), true); $accessToken = $tokenData['access_token']; // 第二步:创建订单 try { $orderResponse = $client->post('https://api-m.sandbox.paypal.com/v2/checkout/orders', [ 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $accessToken ], 'json' => [ "intent" => "CAPTURE", "purchase_units" => [[ "amount" => [ "currency_code" => "USD", "value" => "10.00" ] ]] ] ]); $orderData = json_decode($orderResponse->getBody(), true); dd($orderData); } catch (\GuzzleHttp\Exception\ClientException $e) { // 打印详细错误信息用于排查 dd(json_decode($e->getResponse()->getBody(), true)); }
注意事项:
- 必须使用
json参数传递请求体,而非form_params,同时确保请求头Content-Type为application/json。 - 检查
purchase_units、amount的结构是否完全符合 PayPal v2 规范,避免拼写错误或参数缺失。
参考规范
- PayPal v2 订单 API:重点关注创建订单、捕获订单的参数结构与必填项
- Laravel 官方文档:API 响应格式、CSRF 保护的规范要求
内容的提问来源于stack exchange,提问作者Abdallah
相关产品推荐
相关产品推荐

