Next.js 14集成PayPal授权后捕获订单失败求助
解决PayPal先授权后付款的捕获接口错误问题
你遇到的RESOURCE_NOT_FOUND错误核心原因是调用捕获接口时用错了ID:PayPal的/v2/payments/authorizations/{authorizationId}/capture接口需要的是授权ID,而不是你当前传递的订单ID(orderId)。
下面是具体的修复步骤:
1. 前端修改:保存授权ID而非仅订单ID
在onApprove回调中,从授权返回的详情里提取真正的授权ID并保存,替换原来只存orderId的逻辑:
export const PPButton: FC<PaypalButtonProps> = ({ amount }) => { const [orderId, setOrderId] = useState<string>() // 新增状态保存授权ID const [authorizationId, setAuthorizationId] = useState<string>() const createOrder = (data: Record<string, unknown>, actions: any) => { return actions.order .create({ intent: 'AUTHORIZE', purchase_units: [ { amount: { value: amount, }, } ] }) .then((orderID: string) => { setOrderId(orderID) return orderID; }) .catch((error: any) => { console.error('Error creating order:', error); toast.error('Error creating order'); }); } const onApprove = (data: any, actions: any) => { console.log('data', data); return actions.order.authorize().then((details: any) => { console.log('Authorization details:', details); // 从详情中提取授权ID并保存 const authId = details.purchase_units[0].payments.authorizations[0].id; setAuthorizationId(authId); toast.success('Payment authorized'); }).catch((error: any) => { console.error('Error authorizing order:', error); toast.error('Error authorizing order'); }); } async function onCapture () { // 先判断是否有授权ID if (!authorizationId) { toast.error('未找到已授权的付款记录'); return; } return fetch(`${process.env.NEXT_PUBLIC_HOST}/api/paypal/captureOrder`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ authorizationId // 传递授权ID而非订单ID }), }) .then((response) => response.json()) .then((orderData) => { toast.success('Order paid successfully') }) } return ( <div> <PayPalScriptProvider options={{ intent: 'authorize', clientId: process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID!}}> <PayPalButtons createOrder={createOrder} onApprove={onApprove} /> </PayPalScriptProvider> <button onClick={onCapture}>Capture</button> </div> ); };
2. 后端修改:接收授权ID并调用正确接口
更新你的捕获接口逻辑,接收前端传递的authorizationId,并使用它调用PayPal的捕获接口:
// 捕获订单的路由处理函数 async function captureOrder(req: NextApiRequest, res: NextApiResponse) { try { // 接收authorizationId而非orderId const { authorizationId } = req.body; const accessToken = await generateAccessToken(); // 确保环境和前端一致(沙箱/生产) const base = process.env.PAYPAL_ENV === 'sandbox' ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com'; // 使用authorizationId拼接接口路径 const url = `${base}/v2/payments/authorizations/${authorizationId}/capture`; const response = await fetch(url, { method: 'post', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}`, }, body: JSON.stringify({ payment_instruction: { disbursement_mode: "INSTANT", platform_fees: [ { amount: { currency_code: "EUR", value: "1000" } } ] } }) }); const result = await handleResponse(response); res.status(200).json(result); } catch (error) { console.error('Error in capturing the Paypal order', error); res.status(500).json({ error: 'Capture failed' }); } }
额外检查项
- 环境一致性:确保前端使用的PayPal客户端ID和后端生成accessToken用的密钥属于同一环境(沙箱/生产),跨环境调用会导致资源找不到。
- 授权状态验证:在PayPal沙箱后台查看对应订单,确认授权状态为
COMPLETED后再尝试捕获。 - 参数传递验证:在前端
onCapture和后端接口中打印传递的authorizationId,确认ID没有被截断或修改。
内容的提问来源于stack exchange,提问作者Miriam
相关产品推荐
相关产品推荐

