如何通过PayPal REST API获取IPN等效变量至Django视图?
嘿,刚好我之前在Django项目里用PayPal REST API处理过类似需求,给你梳理清楚怎么搞定这些旧IPN风格的字段~
结论:确实需要用Webhook来获取这些详细数据
客户端的onAuthorize只能拿到基础的授权/订单ID,像手续费(mc_fee)、买家邮箱这类敏感或详细的交易数据,PayPal不会直接返回给前端,必须通过Webhook让PayPal主动把数据推送到你的后端。
第一步:在PayPal开发者后台配置Webhook
- 登录PayPal开发者仪表盘,找到你的REST应用
- 进入「Webhooks」选项卡,点击「Create Webhook」
- 设置你的后端接收URL(必须是HTTPS,本地测试可以用ngrok生成临时HTTPS地址,比如
https://xxxx.ngrok.io/paypal-webhook/) - 勾选需要监听的事件,重点选
PAYMENT.SALE.COMPLETED——这个事件会在交易完成后触发,包含你需要的所有字段 - 保存后,复制生成的Webhook ID,后面Django配置会用到
第二步:客户端JS传递自定义custom字段
在创建PayPal订单的时候,把你的自定义标识(比如订单ID)放到purchase_units的custom字段里,这样后续Webhook就能通过这个字段关联到你的本地订单:
paypal.Buttons({ createOrder: function(data, actions) { return actions.order.create({ purchase_units: [{ amount: { value: '99.99' // 你的订单金额 }, custom: 'ORDER_12345' // 这里传你的本地订单ID,用来关联后续数据 }] }); }, onAuthorize: function(data, actions) { // 捕获订单后重定向到你的成功页面,带上订单ID方便后续查询 return actions.order.capture().then(function(details) { window.location.href = '/checkout-complete/?orderId=' + data.orderID; }); } }).render('#paypal-button-container');
第三步:Django后端实现Webhook接收视图
首先安装官方的PayPal Python SDK:
pip install paypalcheckoutsdk
然后在settings.py里配置PayPal参数:
# PayPal配置 PAYPAL_CLIENT_ID = '你的客户端ID' PAYPAL_CLIENT_SECRET = '你的客户端密钥' PAYPAL_WEBHOOK_ID = '刚才复制的Webhook ID' PAYPAL_MODE = 'sandbox' # 生产环境改成'live'
接下来写Webhook处理视图(比如在views.py里):
from django.http import HttpResponse, HttpResponseBadRequest from django.conf import settings from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment, LiveEnvironment from paypalcheckoutsdk.webhooks import VerifyWebhookSignatureRequest import json def paypal_webhook(request): if request.method != 'POST': return HttpResponseBadRequest("仅接受POST请求") # 初始化PayPal客户端 if settings.PAYPAL_MODE == 'sandbox': environment = SandboxEnvironment(client_id=settings.PAYPAL_CLIENT_ID, client_secret=settings.PAYPAL_CLIENT_SECRET) else: environment = LiveEnvironment(client_id=settings.PAYPAL_CLIENT_ID, client_secret=settings.PAYPAL_CLIENT_SECRET) client = PayPalHttpClient(environment) # 构建签名验证请求(必须做,防止伪造请求) verify_request = VerifyWebhookSignatureRequest() verify_request.webhook_id = settings.PAYPAL_WEBHOOK_ID # 从请求头获取PayPal的验证信息 verify_request.auth_algo = request.headers.get('Paypal-Auth-Algo') verify_request.cert_url = request.headers.get('Paypal-Cert-Url') verify_request.transmission_id = request.headers.get('Paypal-Transmission-Id') verify_request.transmission_sig = request.headers.get('Paypal-Transmission-Sig') verify_request.transmission_time = request.headers.get('Paypal-Transmission-Time') verify_request.webhook_event = json.loads(request.body) try: # 验证Webhook签名 response = client.execute(verify_request) if response.result.verification_status == 'SUCCESS': event = response.result.webhook_event # 只处理交易完成的事件 if event.event_type == 'PAYMENT.SALE.COMPLETED': sale_data = event.resource # 提取你需要的所有字段 custom = sale_data.purchase_units[0].custom mc_fee = sale_data.transaction_fee.value email = sale_data.payer.email_address first_name = sale_data.payer.name.given_name last_name = sale_data.payer.name.surname # 这里把数据保存到数据库,关联到你的订单 # 比如: # from .models import Order # order = Order.objects.get(id=custom) # order.paypal_email = email # order.paypal_fee = mc_fee # order.buyer_first_name = first_name # order.buyer_last_name = last_name # order.save() return HttpResponse("Webhook处理成功") else: # 忽略其他类型的事件 return HttpResponse("未处理该事件类型") else: return HttpResponseBadRequest("无效的Webhook签名") except Exception as e: return HttpResponseBadRequest(f"处理Webhook出错:{str(e)}")
别忘了在urls.py里配置Webhook的路由:
from django.urls import path from . import views urlpatterns = [ # 其他路由... path('paypal-webhook/', views.paypal_webhook, name='paypal_webhook'), path('checkout-complete/', views.checkout_complete, name='checkout_complete'), ]
第四步:在checkout_complete视图中获取数据
当用户被重定向到checkout_complete页面时,你可以通过订单ID查询数据库里已保存的Webhook数据,然后展示给用户:
from django.shortcuts import render, get_object_or_404 from .models import Order def checkout_complete(request): paypal_order_id = request.GET.get('orderId') # 这里可以根据PayPal订单ID或者之前的custom字段查询订单 # 比如如果你把PayPal订单ID存在Order模型里: order = get_object_or_404(Order, paypal_order_id=paypal_order_id) # 把需要的变量传给模板 context = { 'order': order, 'buyer_email': order.paypal_email, 'buyer_name': f"{order.buyer_first_name} {order.buyer_last_name}", 'paypal_fee': order.paypal_fee } return render(request, 'checkout_complete.html', context)
一些关键注意事项
- 必须验证Webhook签名:这是防止恶意请求的关键,绝对不能跳过
- 本地测试用ngrok:PayPal只支持给HTTPS地址发送Webhook,所以本地开发时用ngrok把你的Django端口(比如8000)转成HTTPS地址
- Webhook的可靠性:相比前端回调,Webhook是PayPal主动推送的,即使前端因为网络问题没收到回调,后端也能拿到交易数据,更可靠
内容的提问来源于stack exchange,提问作者MAB
相关产品推荐
相关产品推荐

