代码 微信支付交易账单对账排查:下载链接 5 分钟、GZIP 解不开、金额单位是「元」

2026-10-10 09:01:16

微信支付交易账单对账排查:下载链接 5 分钟、GZIP 解不开、金额单位是「元」

对账那天最常见的三个现场:download_url 过期拿回 403、gunzip 报 not in gzip format、库里的 1000 和账单里的 0.01 差 100 倍。下面按「申请账单 → 下载 → 校验 → 解析 → 逐笔比对」的顺序把这几处过一遍。

接口细节以微信支付 V3 官方文档为准(APIv3 目录下的「申请交易账单 / 下载账单」,见 https://pay.weixin.qq.com/ )。本文未在本机对每个字段逐条实测,接入前建议先拿一个小商户号跑一遍全链路。

一、账单接口返回的是什么

申请交易账单是 GET /v3/bill/tradebill,两个必填查询参数:

  • bill_date:账单日期,YYYY-MM-DD,只能查近 3 个月内;且是 T+1,今天的账单要明天才能申请。
  • bill_type:ALL(含退款)等,按需选。

可选 tar_type=GZIP,让返回的下载链接指向压缩包。

响应里最关键的是三个字段:download_url、hash_type(当前是 sha1)、hash_value。拿到这三个,剩下是「下载 → 校验 → 解压 → 解析」四步,坑全在这四步里。

二、download_url 只有 5 分钟

download_url 是带临时签名的地址,有效期约 5 分钟。典型翻车:把它当普通 URL 丢进延迟队列或落库,worker 半小时后才去下载,拿回一个 403 或错误页。

规则:申请到就立刻下,下载和申请放同一个任务里;要缓存就缓存整个文件内容,不要缓存 URL。需要重试就重新申请一次账单(同一天同类型可重复申请,注意接口频控)。

三、GZIP 解不开,多半是存成了 HTML

download_url 返回的是 GZIP 流。别用「把响应体解成字符串再写盘」的写法:

curl -sS -o bill.gz "$DOWNLOAD_URL"
file bill.gz                      # 期望: gzip compressed data
gunzip -c bill.gz > bill.csv
head -n 2 bill.csv

gunzip 报 not in gzip format,八成存下来的是 HTML:用浏览器直接打开链接、中间有 WAF/代理拦截返回了错误页、或代码里先把响应体 utf8 解码再写文件。先 file bill.gz 和 head -c 200 bill.gz 看头几个字节,别急着调 curl 参数。

四、hash 校验

拿到文件先算摘要,和响应里的 hash_value 比:

sha1sum bill.gz
# 与申请接口返回的 hash_value 逐字符比对

对不上就别入库——说明下载过程被改动或被中间设备替换。对上了再解压。

五、账单金额单位是「元」

接口侧的长期反差:微信支付接口(下单/退款/查单)金额字段 amount.total 单位是「分」的整数,而下载的交易账单文件里,金额是「元」的两位小数。

拿接口的 1000 分去比账单里的 0.01 元,必然差 100 倍。正确做法:解析账单时按「元 × 100 → 分」(或全程 Decimal)统一到最小单位,再和库里的订单金额比。这正是「差正好 100 倍」最常见的原因之一。

六、账单里没有这笔单

  • 只有成功流水:未支付、已关闭、支付失败的订单不会出现在交易账单里。库里查到一笔 trade_state != SUCCESS 的单,账单里没有是正常的。
  • 退款自成一行,不和原支付行合并。按「商户订单号」聚合时会看到同一个 out_trade_no 多行(支付 + 退款),金额一正一负。
  • 金额列里含手续费、代金券/立减等独立字段(以实际表头为准)。对账差几分钱常常是漏算手续费列,或把代金券立减当成了实收。
  • 表尾有汇总行(总单数、总结算金额等)。解析时要么按固定行数处理,要么显式跳过最后一行,否则汇总行会被当成一笔异常订单。

对账口径:库里「支付成功」的订单集合,应等于账单里支付行的集合。差额分三类——库里多(多为通知丢了但实际支付成功的单,去查单补)、账单多(多为未入库成功的单,人工补单/补发)、金额差异(多为单位或手续费口径)。

七、对不平时的排查顺序

  1. 先确认账单日期与类型对不对(ALL 才含退款)。
  2. 单位口径:两边是否都换算到了「分」。
  3. 聚合维度:按 out_trade_no 聚合,退款行单独处理。
  4. 差单:用库里的订单号去账单里反查,命不中的看该单 trade_state。
  5. 差钱:用同一笔单的账单行和接口查单结果对,定位是单位、手续费还是优惠口径。

八、不适用 / 未实测

  • bill_type 的完整取值、汇总行的字段名与顺序、tar_type 的默认行为,均以官方最新文档为准;本文未在本机逐字段核对。
  • 「账单金额单位是元」按文档口径处理;资金账单(如 fundflowbill)字段与交易账单不完全一样,别把交易账单的解析代码直接套过去。
  • 5 分钟有效期是文档值,实际以你收到的报错为准:过期一般表现为下载 403 或空内容。

推荐文章

程序员茄子在线接单