You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中实现NETS支付webhook 解决支付确认及页面重载问题

首先明确webhook的运行逻辑:它不是你需要主动发起的轮询请求,是NETS平台在支付状态发生变更时,主动向你预先配置的服务器地址发送的POST回调请求,你只需要提供一个公网可访问的接口接收这个请求,更新对应订单的支付状态即可。

具体实现步骤

1. 新增专属Webhook视图和路由

不要把webhook处理逻辑塞到现有Payment视图里,单独创建一个视图专门处理NETS回调,需要豁免CSRF校验(第三方平台请求不会携带你的站点CSRF Token),同时校验请求头的Authorization字段防止伪造请求:

import json
from django.views import View
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
# 导入你自己的订单工具类/模型

@method_decorator(csrf_exempt, name='dispatch')
class NETSWebhookView(View):
    # 自行生成8-32位字母数字串作为校验密钥,建议存在Django settings中不要硬编码
    WEBHOOK_AUTH_KEY = "自行生成的随机字母数字串"

    def post(self, request, session_id, *args, **kwargs):
        # 校验请求合法性,防止恶意伪造回调
        if request.headers.get("Authorization") != self.WEBHOOK_AUTH_KEY:
            return HttpResponse(status=403)
        
        # 解析回调事件数据
        event = json.loads(request.body)
        # 判断是否为支付完成事件,事件名以NETS官方文档为准
        if event.get("eventName") == "payment.completed":
            # 更新对应session订单的支付状态为已支付
            webshopUtils.update_order_payment_status(
                session_id_key=session_id,
                status="paid"
            )
        
        # 必须返回200状态码,否则NETS会认为回调失败重复发送请求
        return HttpResponse(status=200)

在urls.py中添加对应路由,路由路径中携带session_id参数,这样NETS回调时你可以直接从路径中拿到标识关联对应订单:

urlpatterns = [
    # 原有路由保持不变
    path("nets-webhook/<str:session_id>/", views.NETSWebhookView.as_view(), name="nets_webhook"),
]

注意:生产环境该地址必须为HTTPS,本地开发可使用ngrok等内网穿透工具获取临时公网HTTPS地址测试。

2. 创建支付ID时注册Webhook

修改你调用get_paymentId的代码,补上notifications参数,把刚才配置的webhook地址注册到NETS:

# 拼接webhook公网地址,生产环境替换为你自己的站点域名
webhook_url = f"https://你的站点域名/nets-webhook/{session_id_key}/"
notifications_params = {
    "webhooks": [
        {
            "eventName": "payment.completed",
            "url": webhook_url,
            "authorization": NETSWebhookView.WEBHOOK_AUTH_KEY
        }
    ]
}

# 调用创建支付接口时传入notifications参数
paymentId = payment.get_paymentId(
    platform = platform,
    reference = reference, 
    name = 'Hidden Dimsum 2900 Takeaway',
    paymentReference = session_id_key,
    unitPrice = int(totalPrice) *100,
    notifications = notifications_params # 新增该参数
)

3. 修改现有Payment视图逻辑

你原来留空的elif分支不需要放webhook处理逻辑,这里是用户跳转回站点的访问场景,直接查询当前订单的支付状态做跳转即可,解决用户刷新页面重复生成支付单的问题:

elif ('deliveryForm' not in request.GET) and ('pickupForm' not in request.GET):
    # 查询当前session对应的订单支付状态
    current_order = webshopUtils.get_order(session_id_key=request.session[session_id_key])
    # 已支付直接跳转到支付完成页,不再生成新的支付ID
    if current_order.payment_status == "paid":
        return redirect("paymentComplete")

4. 兼容原有前端逻辑

原有JS的支付完成跳转逻辑可以保留,webhook作为兜底方案:即使用户刷新页面、中途关闭支付页再回来,只要NETS已经推送了支付完成的回调,后台订单状态已经更新,用户访问支付页就会直接跳转到完成页,不会出现JS失效无法跳转的问题。

内容的提问来源于stack exchange,提问作者jxw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 07:30:02