支付宝沙箱以Django框架为例
在电商平台的开发阶段,在确认订单后的支付跳转不需要接入真实的支付接口,更推荐使用支付平台的沙箱环境或模拟支付流程来完成功能开发和测试。开发阶段功能尚未稳定,直接接入真实支付接口可能导致误操作产生真实交易(如测试时误支付),甚至存在安全漏洞风险。主流支付平台(如支付宝、微信支付)都提供沙箱测试环境,支持模拟支付流程(包括支付成功、失败、退款等场景),且不会真实资金流动,完全能满足开发阶段的功能验证需求。本文章以Python中的Django框架为例进行演示。
1. 准备阶段
1.1 登录支付宝开放平台
登录支付宝开放平台官网 ——> 点击控制台 ——> 沙箱

1.2 下载密钥工具

安装完成后生成密钥:

RSA2 加密算法默认生成格式为 PKCS8(Java适用),如需 PKCS1 格式(非Java适用),可使用 格式转换。

1.3 配置密钥
点击自定义密钥——>公钥模式——>设置并查看,将密钥工具生成的应用公钥复制到这里,再点击保存

1.4 下载沙盒版APP
沙箱工具首页 - 开放平台,下载APP是一个可选操作,个人觉得这样在后续的测试支付更方便一些。
1.5 沙箱版账号
支付宝会给你卖家和买家两个账号,包括账号以及密码,可自定义的余额。用于支付测试。
2. 创建项目
2.1 新建应用
创建一个名为demo的应用
python manage.py startapp demo
2.2 安装支付宝官方SDK
pip3 install alipay-sdk-python
2.3 新建keys目录
项目下创建新文件keys,存放应用私钥和支付宝公钥文件。
支付宝公钥文件alipay_public_key.pem
格式:
-----BEGIN PUBLIC KEY-----
你的支付宝公钥
-----END PUBLIC KEY-----
应用私钥文件app_private_key.pem
格式:
-----BEGIN RSA PRIVATE KEY-----
你的应用私钥
-----END RSA PRIVATE KEY-----
2.4 项目结构
示例项目结构如下:
alipay_demo/ # 项目根目录
├── alipay/ # 主配置目录
│ ├── settings.py
│ ├── urls.py
│ └── ...
├── demo/ # 应用(新建)
│ ├── models.py # 订单模型
│ ├── views.py # 支付相关视图
│ ├── templates # 支付模板
│ └── urls.py
├── keys/ # 存放密钥(新建)
│ ├── app_private_key.pem # 应用私钥
│ └── alipay_public_key.pem # 支付宝公钥
└── manage.py
3. 项目配置
在settings.py文件中进行以下配置
3.1 注册应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'demo', # 注册demo应用
]
3.2 支付宝沙箱配置
# 支付宝沙箱配置
ALIPAY_SETTINGS = {
"appid": "9021000155669214",
"app_return_url": "http://项目公网地址/pay/success/", # 同步回调地址
"app_notify_url": "http://项目公网地址/alipay/notify/", # 异步回调地址
"app_private_key_path": os.path.join(BASE_DIR, "keys/app_private_key.pem"), # 应用私钥路径
"alipay_public_key_path": os.path.join(BASE_DIR, "keys/alipay_public_key.pem"), # 支付宝公钥路径
"sign_type": "RSA2", # 签名方式
"debug": True, # 沙箱环境为True
}
# 读取密钥内容
from Crypto.PublicKey import RSA
# 1. 读取应用私钥
with open(ALIPAY_SETTINGS['app_private_key_path'], 'r') as f:
app_private_key_content = f.read()
private_key = RSA.import_key(app_private_key_content) # 主要是对文件内容进行处理,移除空格,换行,以及类似-----BEGIN PUBLIC KEY-----的样式
app_private_key = private_key.export_key().decode('utf-8')
ALIPAY_SETTINGS['app_private_key'] = app_private_key
# 2. 读取支付宝公钥
with open(ALIPAY_SETTINGS['alipay_public_key_path'], 'r') as f:
alipay_public_key_content = f.read()
public_key = RSA.import_key(alipay_public_key_content)
alipay_public_key = public_key.export_key().decode('utf-8')
ALIPAY_SETTINGS['alipay_public_key'] = alipay_public_key
3.3 URL设计
urls.py文件示例:
urlpatterns = [
path('admin/', admin.site.urls),
path('product/', views.product, name="product"),
path('order/<int:product_id>/', views.order, name="order"),
path('order_list/', views.order_list, name="order_list"),
path('alipay/notify/', views.alipay_notify, name="alipay_notify"),
path('pay/result/', views.alipay_return, name="alipay_return"),
path('pay/<str:order_id>/', views.pay, name="pay"), # 字符串类型,且需要放在最后一位
]
4. 数据库模型设计
这里仅简单的设计了一些必要的数据库表和字段作为演示。
4.1 商品表Product
class Product(models.Model):
name = models.CharField(max_length=256)
price = models.DecimalField(max_digits=11, decimal_places=2) # 精确到分(支付宝限制参数)
4.2 订单表Order
class Order(models.Model):
order_id = models.CharField(max_length=64, unique=True)
total_amount = models.DecimalField(max_digits=11, decimal_places=2) # 精确到分(支付宝限制参数)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
# 订单状态选择:待支付、已支付、已取消
ORDER_STATUS_CHOICES = [
("待支付", "待支付"),
("已支付", "已支付"),
("已取消", "已取消"),
]
status = models.CharField(max_length=20, default="待支付", choices=ORDER_STATUS_CHOICES)
created_at = models.DateTimeField(auto_now_add=True)
# 单号随机生成且不重复,使用uuid4
def save(self, *args, **kwargs):
if not self.order_id:
self.order_id = f"{uuid.uuid4().hex[:16].upper()}"
super().save(*args, **kwargs)
4.3 注册admin
在admin后台页面显示Product和Order表,方便以后的测试。
在admin.py添加以下代码:
from django.contrib import admin
from .models import Product, Order
admin.site.register(Product)
admin.site.register(Order)
创建后台超级用户进行登录
python manage.py createsuperuser
然后随便添加一个测试商品用于后续测试(略)
5. 前端模板
移步至另外一个博客:沙盒前端附件-CSDN博客
6. 后端代码
6.1 初始化客户端
初始化Alipay客户端,传入setting中配置好的参数。
# 初始化客户端配置对象AlipayClientConfig
alipay_client_config = AlipayClientConfig() # 初始化支付宝客户端配置对象
alipay_client_config.server_url = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do' # 沙箱环境 正式环境为:'https://openapi.alipay.com/gateway.do'
alipay_client_config.app_id = settings.ALIPAY_SETTINGS['appid'] # 应用ID
alipay_client_config.app_private_key = settings.ALIPAY_SETTINGS['app_private_key'] # 应用私钥
alipay_client_config.alipay_public_key = settings.ALIPAY_SETTINGS['alipay_public_key'] # 支付宝公钥
alipay_client_config.sign_type = settings.ALIPAY_SETTINGS['sign_type'] # 签名类型(默认RSA2)
# 创建客户端DefaultAlipayClient实例(一个配置对应一个客户端,配置不可动态修改)
# 如果想使用不同的配置,请定义不同的DefaultAlipayClient
alipay_client = DefaultAlipayClient(alipay_client_config) # 创建默认的支付宝客户端对象实例
6.2 实现网站支付接口
电脑网站支付接口:alipay.trade.page.pay,官方参考文档:沙箱调试说明 - 支付宝文档中心
请求参数(部分):
| 参数名 | 是否必选 | 数据类型 | 描述 | 示例值 |
|---|---|---|---|---|
| out_trade_no | 必选 | string(64) | 商户自定义订单号,仅支持字母、数字、下划线,需保证商户端唯一 | 20150320010101001 |
| total_amount | 必选 | price(11) | 订单总金额(单位:元),精确到小数点后两位,取值范围 [0.01,100000000],不可为 0 | 88.88 |
| subject | 必选 | string(256) | 订单标题,不可使用 /、=、& 等特殊字符 | Iphone6 16G |
| product_code | 必选 | string(64) | 销售产品码,电脑支付场景仅支持 FAST_INSTANT_TRADE_PAY | FAST_INSTANT_TRADE_PAY |
| qr_pay_mode | 可选 | string(2) | PC 扫码支付方式,枚举值:0(简约前置,iframe≥600px×300px)、1(前置,iframe≥300px×600px)、3(迷你前置,iframe≥75px×75px)、4(可定义宽度嵌入式)、2(跳转模式) | 1 |
| qrcode_width | 可选 | number(4) | 商户自定义二维码宽度,仅 qr_pay_mode=4 时有效 | 100 |
其中订单号out_trade_no,订单金额total_amount,订单标题subject以及产品码product_code是必须传递给支付宝服务器的参数。更多详细参数请自行访问官方文档。
6.3 实现支付跳转
当前端页面点击支付按钮时发送POST请求,需要将订单信息通过接口传递给支付宝服务器并实现支付宝支付页面的跳转。
def pay(request, order_id):
if request.method == 'POST':
# 获取订单数据
order = Order.objects.get(order_id=order_id)
# 1. 创建订单参数模型(AlipayTradePagePayModel)
page_pay_model = AlipayTradePagePayModel()
page_pay_model.out_trade_no = order_id # 商户订单号(唯一)
page_pay_model.total_amount = "{0:.2f}".format(order.total_amount) # 订单金额
page_pay_model.subject = order.product.name # 订单标题
page_pay_model.product_code = "FAST_INSTANT_TRADE_PAY" # 销售产品码,电脑网站固定为FAST_INSTANT_TRADE_PAY
# 2. 创建支付请求对象
page_pay_request = AlipayTradePagePayRequest(biz_model=page_pay_model) # 关联订单参数模型
page_pay_request.return_url = settings.ALIPAY_SETTINGS["app_return_url"] # 同步回调地址(用户支付后跳转)
page_pay_request.notify_url = settings.ALIPAY_SETTINGS["app_notify_url"] # 异步通知地址(核心状态通知)
# 3. 生成支付链接,前端跳转支付页面
pay_url = alipay_client.page_execute(page_pay_request, http_method='GET') # 调用page_execute方法生成支付链接(http_method可选"GET"或"POST")
return HttpResponse(f'<script>window.location.href="{pay_url}";</script>') # 返回支付URL,前端跳转至支付宝支付页面
将订单参数发送到支付宝服务器时,可以选择GET也可以选则POST方法,page_execute方法会自动处理参数的签名和拼接:
- 当
http_method='GET'时,生成的pay_url已经包含了所有必要参数(商户订单号、金额、签名等),直接跳转即可; - 当
http_method='POST'时,会生成一个包含参数的 HTML 表单,需要通过表单提交(form.submit())触发 POST 请求。
如果需要更严格地控制参数传递(例如避免参数在 URL 中明文显示,虽然签名已保证安全性),可以改用POST。
6.4 处理同步跳转
用户在支付宝完成支付(或取消支付)后,支付宝会自动将用户浏览器跳转回开发者在请求中指定的return_url页面。主要作用是给用户提供即时的支付结果反馈,比如显示 “支付成功” 或 “支付取消” 的页面。不能作为交易最终成功的依据。同步跳转建议进行验签操作,有效防止参数被恶意篡改,避免用户被虚假的支付结果误导。但主要还是实现支付成功/失败页面的跳转。
请求方式:GET 或 POST(推荐 POST,避免参数暴露)
请求地址:
- 正式环境:
https://openapi.alipay.com/gateway.do - 沙箱环境:
https://openapi.alipaydev.com/gateway.do
请求参数:
- 示例:
https://openhome.alipay.com/platform/home.htm?charset=utf-8&out_trade_no=page20187272054511544764&method=alipay.trade.page.pay.return&total_amount=0.01&sign=QGyeDPIpPnBkEVQKGAGNTxZ4Tvo0NWgPH6AVk6C9mQC0EzfkeLbW7riaaWavEAhxpja%2Fajmv%2Fd0v%2FLjGWZYmAhjmb%2FNw1PN1UlLqbZzrDTGY90HRmC4vhzxTAsU3SdSDiSsOMDAuGzXyCgp4YP8p7bmKjYV7UWLGsTi8qwTApYEk0GtPtn2EboEDvJR1VCEFI2Mk696%2FiEIkark25ldlrTu%2BcwdpLihLsKK7UcyUApKuy93NeBSXy801HBokg36RUhOC45goaYuiWvI1L6CP1pvuRSVGWHfsRiewDJJu2t9fnfogS6xSpatcYyUac2U1j7DHChAeX9XLKVj44g4Fyw%3D%3D&trade_no=2020032622001409860523801721&auth_app_id=2014**********22&version=1.0&app_id=2014**********22&sign_type=RSA2&seller_id=2088**********35×tamp=2020-03-26+16%3A32%3A04
| 参数类别 | 参数名 | 示例值(来自 URL) | 核心含义 |
|---|---|---|---|
| 基础参数 | app_id | 2014****22 | 商户在支付宝的唯一标识,与发起支付时的 app_id 一致 |
| method | alipay.trade.page.pay.return | 接口名称,固定表示 “电脑支付同步回调” | |
| charset | utf-8 | 参数编码格式,需与发起支付时的编码一致 | |
| version | 1.0 | 接口版本,固定为 1.0 | |
| sign_type | RSA2 | 签名算法,此处为推荐的 RSA2(SHA256withRSA),与发起支付时的签名类型一致 | |
| 业务结果参数 | out_trade_no | page20187272054511544764 | 商户自定义的订单号,与发起支付时传入的订单号完全一致,用于关联本地订单 |
| trade_no | 2020032622001409860523801721 | 支付宝生成的唯一交易号,可用于查询、退款等后续操作 | |
| total_amount | 0.01 | 订单实际支付金额,单位为元,需与商户订单金额核对 | |
| seller_id | 2088****35 | 收款商户的支付宝账号 ID,需确认是否为自身商户 ID,防止串号 | |
| timestamp | 2020-03-26 16:32:04 | 回调通知的时间,格式为 “yyyy-MM-dd HH:mm:ss” | |
| auth_app_id | 2014****22 | 授权方 app_id,若为直连商户则与 app_id 一致 | |
| 安全验证参数 | sign | QGyeDPIpPnBkEVQKGAGNTxZ4... | 对所有参数按支付宝规则生成的签名,必须验证以确保参数未被篡改 |
# 通知参数处理函数
def get_dic_sorted_params(org_dic_params):
content = ''
org_dic_params.pop('sign')
org_dic_params.pop('sign_type') # 去除sign、sigh_type
new_list = sorted(org_dic_params, reverse=False) # 待验签参数进行排序
for i in new_list:
p = i + '=' + org_dic_params.get(i) + '&'
content += p
sorted_params = content.strip('&') # 重组字符串,将{k:v}形式的字典类型原始响应值--》转换成'k1=v1&k2=v2'形式的字符串格式
return sorted_params
# 支付宝同步通知回调视图函数
def alipay_return(request):
# 获取支付宝返回的所有参数
params = request.GET.dict()
# 提取签名
sign = params.get('sign')
# 对通知参数进行处理
org_message = get_dic_sorted_params(params)
# 转换成字节串
message = bytes(org_message, encoding='utf-8')
# 验证签名(同步回调参数不包含trade_status只需验证签名通过,即可认为支付流程完成)
verified = verify_with_rsa(
public_key=settings.ALIPAY_SETTINGS['alipay_public_key'],
message=message,
sign=sign,
)
print('同步', params)
if verified:
# 验签成功且交易状态有效(仅用于前端展示)
order_id = params.get("out_trade_no") # 商户订单号
order = get_object_or_404(Order, order_id=order_id)
return render(request, "success.html", {"order": order})
else:
# 验签失败或交易状态异常
return render(request, "fail.html")
6.5 处理异步通知
支付宝在确认交易状态(如支付成功、退款成功)后,会主动向开发者后台预先配置的notify_url发送 POST 请求,传递交易详情。需要定义对应的视图函数处理支付宝发送的消息。这个消息也是作为开发者后台更新订单状态的唯一可靠依据,确保即使同步跳转失败,系统也能准确获知交易结果。
收到notify_url的请求后,必须使用支付宝公钥验证请求参数的签名,防止伪造通知篡改订单状态。收到异步通知并处理完成后,必须返回 “success” 字符串(不包含任何其他字符),否则支付宝会持续重试。
请求方式:POST
请求参数:
| 参数类别 | 参数名 | 示例值 | 核心含义 |
|---|---|---|---|
| 基础信息参数 | app_id | 9021XXXXXX669214 | 商户在支付宝的唯一标识,需与发起支付时的app_id一致 |
| charset | utf-8 | 编码格式,固定为 utf-8 | |
| version | 1.0 | 接口版本,固定为 1.0 | |
| notify_time | 2025-10-19 15:20:01 | 通知发送时间,格式 “yyyy-MM-dd HH:mm:ss” | |
| notify_type | trade_status_sync | 通知类型,固定为 “交易状态同步” | |
| notify_id | 2025101901222152001092760507420654 | 通知唯一 ID,用于调用支付宝接口验证通知合法性(必验) | |
| auth_app_id | 9021000155669214 | 授权方 app_id,直连商户与app_id一致 |
|
| 交易状态参数 | out_trade_no | 1166ECBA0A6B4FD2 | 商户自定义订单号,与发起支付时的订单号完全一致(用于关联本地订单) |
| trade_no | 2025101922001492760507427663 | 支付宝生成的唯一交易号,可用于后续查询、退款等操作 | |
| trade_status | TRADE_SUCCESS | 交易状态(核心参数),表示 “支付成功”(其他状态:TRADE_CLOSED 交易关闭等) | |
| gmt_create | 2025-10-19 15:19:53 | 订单创建时间 | |
| gmt_payment | 2025-10-19 15:20:00 | 支付完成时间(与trade_status=TRADE_SUCCESS对应) |
|
| buyer_id | 2088722082392766 | 买家支付宝账号 ID(脱敏) | |
| seller_id | 2088721082362450 | 卖家支付宝账号 ID(需确认是否为当前商户,防止串号) | |
| 金额相关参数 | total_amount | 99.00 | 订单总金额(元),需与商户本地订单金额核对(防止金额篡改) |
| buyer_pay_amount | 99.00 | 买家实际支付金额(元,与total_amount一致,无折扣时相等) |
|
| receipt_amount | 99.00 | 商户实际收到的金额(元,扣除手续费前) | |
| invoice_amount | 99.00 | 可开发票金额(元) | |
| point_amount | 0.00 | 使用积分支付的金额(元,此处未使用积分) | |
| fund_bill_list | [{"amount":"99.00","fundChannel":"ALIPAYACCOUNT"}] | 支付渠道明细,此处为 “支付宝账户” 支付 99 元 | |
| 业务描述参数 | subject | 测试商品 | 订单标题,与发起支付时的subject一致 |
| 安全验证参数(必含,示例隐去) | sign | (实际会有 RSA2 签名值) | 对所有参数的签名,需验证其合法性(防篡改) |
| sign_type | RSA2 | 签名算法,与商户配置一致(推荐 RSA2) |
异步通知视图需要实现以下功能:
-
接收支付宝发送来的POST请求。
-
对请求参数按要求处理并验证签名(确保支付相关数据的安全性与真实性)。
-
更新业务数据。
# 支付宝异步通知回调视图函数
@csrf_exempt # 禁用CSRF防护,确保支付宝异步通知可以正常接收
def alipay_notify(request):
if request.method == 'POST':
# 1. 获取支付宝发送的通知参数(POST形式)
params = request.POST.dict()
# 2. 提取签名(用于验证)
sign = params.get('sign')
# 3. 对通知参数进行处理
org_message = get_dic_sorted_params(params)
# 4. 转换成字节串
message = bytes(org_message, encoding='utf-8')
# 5. verify_with_rsa方法验证签名
verified = verify_with_rsa(
public_key=settings.ALIPAY_SETTINGS['alipay_public_key'],
message=message,
sign=sign,
)
# 6. 检查验证状态
if not verified:
print("支付宝异步通知:签名验证失败")
return HttpResponse("fail") # 签名验证失败返回fail,这是支付宝接口的硬性要求
trade_status = params.get('trade_status')
if trade_status not in ['TRADE_SUCCESS', 'TRADE_FINISHED']:
logging.info(f"支付未成功,状态:{trade_status}")
return HttpResponse("success") # 支付宝要求非成功状态也返回success
# 7. 数据更新逻辑
try:
out_trade_no = params.get('out_trade_no')
order = Order.objects.get(order_id=out_trade_no)
# 幂等性处理:如果已经支付成功,直接返回
if order.status == "已支付":
return HttpResponse("success")
order.status = "已支付" # 更新订单状态
order.save()
logging.info(f"订单{out_trade_no}支付成功,状态已更新")
except Exception as e:
logging.error(f"处理订单失败:{str(e)}")
return HttpResponse("fail")
return HttpResponse("success")
return HttpResponse("fail") # 非POST请求返回fail
为什么要禁用CSRF防护?会不会造成安全隐患?
CSRF 保护的核心逻辑是:验证请求是否来自 “可信的用户浏览器”,支付宝异步通知是 “服务器对服务器” 的请求,无法携带 CSRF 令牌,不满足 CSRF 验证条件。如果不禁用 CSRF 保护,框架会因为无法验证令牌而直接拒绝支付宝的通知请求,导致业务逻辑无法执行。禁用 CSRF 保护后,安全性由支付宝的签名验证机制保障。
7. 内网穿透
在开发阶段,项目只能在本地进行运行,而不能通过公网访问,虽然是沙盒环境,但也需要把项目暂时暴露在公网中,否则在进行支付时,支付宝服务器无法对我们的项目进行请求。这里推荐使用NATAPP穿透,免费好用。
7.1 软件下载
官方网站:NATAPP-内网穿透 基于ngrok的国内高速内网映射工具

根据自己的操作系统选择对应的按钮。
7.2 注册账户

注册后需要实名认证!
7.3 创建隧道
点击购买隧道——>免费隧道


端口设置为8000,因为Django的端口为8000,如果使用其他框架自行更改!
7.4 开启穿透
成功获取隧道后在我的隧道中会显示隧道的authtoken,复制这个用于后续启动。
下载的软件压缩包进行解压,解压后在natapp.exe程序所在的目录下执行以下命令来启动:
natapp.exe -authtoken=你的隧道的authtoken
启动成功大概这个样子:

成功启动后再运行Django项目即可进行测试了。
记得在settings.py中配置ALLOWED_HOSTS才能正常运行。
ALLOWED_HOSTS = ['公网地址', 'localhost']
8. 流程总结
8.1 支付请求发起
-
前端触发支付用户在页面点击支付按钮后,前端向项目后端发起支付请求,携带订单信息(如
out_trade_no、total_amount、subject)。 -
后端生成支付参数
使用支付宝 SDK 构造请求参数,包含:
{
"app_id": "沙盒APPID",
"method": "alipay.trade.page.pay",
"format": "JSON",
"charset": "UTF-8",
"sign_type": "RSA2",
"timestamp": "2025-10-15 14:30:00",
"version": "1.0",
"biz_content": {
"out_trade_no": "202510150001",
"total_amount": "100.00",
"subject": "测试商品",
"product_code": "FAST_INSTANT_TRADE_PAY",
"timeout_express": "15m" // 沙盒限制超时时间≤15小时
},
"return_url": "https://your-domain.com/pay/success", // 同步跳转地址
"notify_url": "https://your-domain.com/pay/notify" // 异步回调地址
}
使用 应用私钥 对参数进行 RSA2 签名,生成 sign 字段。
- 请求发送至沙盒网关后端将构造好的请求通过 HTTP POST 发送至沙盒网关
https://openapi.alipaydev.com/gateway.do,沙盒网关验证签名和参数合法性。
8.2 沙盒支付界面交互
-
支付页面渲染沙盒网关返回包含支付表单的 HTML 页面,前端通过
window.location.href或嵌入iframe展示该页面。对于移动端,沙盒 APP 会自动唤起支付界面。 -
用户支付操作
用户使用沙盒买家账号(格式为 XXX@sandbox.com,密码 111111)或沙盒版APP扫码完成交易。
-
支付结果反馈
-
支付成功:同步跳转,沙盒网关将页面重定向至项目配置的
return_url,并携带trade_no、out_trade_no等参数。 - 支付失败:页面跳转至错误提示页,或返回错误码(如
INVALID_PARAMETER)。
8.3 异步回调与订单验证
-
沙盒发起异步通知无论支付结果如何,沙盒网关都会向
notify_url发送 POST 请求,携带完整的支付数据。 -
后端验签与业务处理
签名验证:使用 支付宝公钥 验证回调数据的签名,确保数据未被篡改。
状态判断:判断支付状态trade_status是否是TRADE_SUCCESS或者TRADE_FINISHED(这种是无法取消的交易)
幂等性处理:通过数据库唯一索引或状态字段(如 is_processed)避免重复处理同一回调。
- 响应沙盒网关后端处理完成后必须返回
success(全小写),否则沙盒会在 24 小时内重试通知(最多 8 次)。
8.4 前端状态同步与页面跳转
同步跳转处理用户被重定向至 return_url 后,前端通过 URL 参数获取 trade_no,并调用后端接口查询订单状态
8.5 沙盒环境特性与限制
- 支付方式限制沙盒仅支持 余额支付,不支持银行卡、花呗等真实支付方式。测试时需提前通过沙盒控制台为买家账号充值。
- 超时时间约束
timeout_express参数在沙盒环境中需设置为当前时间后 15 小时内,超过此范围会导致支付自动关闭。 - 数据隔离沙盒返回的
user_id、trade_no等数据与生产环境完全独立,严禁在正式环境中使用沙盒数据。
8.6 常见错误
我个人在进行测试时,经常碰见的错误大致就是对数据的处理方面。一些总结:
-
对支付宝公钥和应用私钥文件的数据处理格式问题
-
传递给支付宝服务器时的订单总额参数格式问题
- 同步/异步回调参数的处理时数据格式问题
内容仅供参考,如有错误欢迎指正!
发表评论