沙箱里跑通的代码换到生产报错,绝大多数不是业务逻辑问题,而是几处环境相关的配置没跟着换。通常需要重新过一遍的是四类东西:应用与密钥、接口权限、回调地址、日志与脱敏策略,最后再用一条最小请求把整条链路验证一次。判断依据不要靠读代码,而要靠控制台页面、日志和一次真实请求的响应。
沙箱与生产的凭证、权限、回调地址、日志策略通常是相互独立的两套配置,切环境时至少要把这四类重新核对一遍。是否配齐,建议用一条最小请求打到生产网关来判断:看响应码、看业务返回、看回调有没有落地、看日志里有没有明文密钥。边界是:具体字段名、权限名称和错误码以各环境控制台的实际情况为准,下面的顺序是核对方法,不是可直接复制的凭证。
确认生产环境的应用与密钥是否独立
先回答一个前置问题:沙箱和生产是不是共用同一套凭证。多数开放平台把两者做成隔离的两个应用,沙箱的 AppID、私钥、公钥在正式环境通常不通用,网关地址也往往不同。控制台里应用详情展示什么字段就以什么为准,不要凭记忆写死。
配置文件的组织上,建议按环境拆开,而不是在同一个文件里改来改去。常见做法是用 profile 或环境变量注入,密钥不写进代码仓库:
# application-prod.yaml(示意,字段名以控制台为准)
alipay-ai:
gateway: https://{生产网关域名}
app-id: ${PROD_APP_ID}
private-key: ${PROD_PRIVATE_KEY}
alipay-public-key: ${PROD_ALIPAY_PUBLIC_KEY}
# application-sandbox.yaml
alipay-ai:
gateway: https://{沙箱网关域名}
app-id: ${SANDBOX_APP_ID}
private-key: ${SANDBOX_PRIVATE_KEY}
一个可操作的校验动作:用生产凭证对一笔请求签名后发出,如果返回的是签名校验失败或应用不存在,先怀疑网关地址和私钥是不是还是沙箱那套,再怀疑密钥格式(PKCS1 与 PKCS8、是否带换行)。
逐一核对接口权限在生产是否已开通
权限不随环境自动迁移,这是切换当天最常见的坑。做法是把沙箱里实际调用过的接口逐条列成清单,再拿到生产应用的产品或权限页面去对照勾选,别只凭印象觉得“应该都开了”。清单建议记成三列:接口名或 method、沙箱是否调通、生产是否已开通。
发现缺失时,处理顺序建议是:先确认这项是应用级权限还是需要账号签约的能力;应用级的在控制台按流程申请开通;需要签约的在商户侧或开放平台完成签约后等生效。生效前接口一般会返回无权限、权限不足一类的错误码,这类报错不要当作代码 bug 去调参数。清单没对齐之前,不要进入联调阶段。
替换回调地址并确认外部可达
沙箱里配的回调地址上线后通常不可用,因为那多半是内网地址、测试端口或临时的穿透地址。切换到生产时要做三件事:把回调地址换成生产域名下的正式路径,路径与应用里注册的路由保持一致,协议优先用 https。地址改完不代表就通了,还要验证外部可达性。
可以先在服务器上确认服务确实在监听对应端口,再从外网环境发一条构造请求,确认能打进来、能进到路由、日志能落下来:
curl -i -X POST 'https://{你的生产域名}/notify/alipay-ai' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'biz_content={}&sign=test&sign_type=RSA2'
这条请求的目的是验证链路,签名校验失败是预期结果,不用当成问题。看日志时重点确认几个观察点:请求时间、请求路径、来源、签名校验的结果、以及返回给对方的响应体是不是约定的成功标识。如果日志里完全没有这条记录,说明请求根本没进到应用,先查网关、防火墙和反向代理,再查应用配置。
调整日志与脱敏策略
沙箱阶段为了排查方便,很多人会把完整请求体打出来,这套策略带到生产是不合适的。需要脱敏的字段通常包括:应用私钥及各类密钥、access_token 与 refresh_token、请求签名、用户标识类字段(用户 ID、手机号、姓名、证件号),以及业务参数原文里可能夹带的个人信息。
脱敏建议放在统一的日志封装层做,而不是每个打印点单独判断:
SENSITIVE = {"private_key", "access_token", "refresh_token", "sign", "user_id", "mobile"}
def mask(k, v):
if k in SENSITIVE and isinstance(v, str):
return "***" if len(v) <= 8 else v[:4] + "***" + v[-2:]
return v
上线前检查日志文件的做法很直接:跑完一次请求后,对日志目录做关键词扫描,命中就说明脱敏没覆盖到。
grep -nE 'private_key|BEGIN .*PRIVATE KEY|refresh_token|"mobile"' /var/log/app/app.log
确认干净之后再放量。需要保留排查线索时,用哈希值或后几位代替原文,不要把完整字段留在磁盘上。
用一次最小请求做上线后的首次验证
前面的配置都改完之后,不要一上来就跑完整业务,先用一条最小请求确认整条链路在真实环境可用。骨架大致是这样:
POST {生产网关域名}/gateway.do
Content-Type: application/x-www-form-urlencoded
method={沙箱里已跑通的某个接口}
app_id={生产 appId}
timestamp={当前时间}
sign={用生产私钥对请求串签名}
biz_content={最小可用参数}
成功与失败的判定要分开看。成功的标志是 HTTP 层返回正常,且业务响应码为约定的成功值,返回体里的业务字段符合预期。失败则分三类:网络层打不通、网关层报签名错误或应用不存在、业务层报无权限或参数错误。
失败时按配置项逐条排查,顺序建议是:第一步确认请求确实打到了生产网关而不是沙箱网关;第二步核对 appId 与私钥是否配对;第三步看该接口权限在生产是否已开通;第四步比对签名串与参数是否完全一致,包括空值和编码;第五步回到回调,确认对方异步通知能落到生产地址并写进日志。按这个顺序走,多数切换当天的问题都能定位到具体哪个配置项上。