# Webhook 接收器 — 说明 路径:`pages/mall/delivery/webhook-server/webhook-receiver.js` 目的:接收承运方或 Mock Server 的 HTTP 回调(POST /webhook/express/status),将原始回文写入 `platform_express_event_raw`,并按项目现有映射更新 `platform_express_waybills` 与写入 `platform_express_tracking_events`。 环境变量(必须/可选): - `SUPA_URL`:Supabase REST 地址(示例 `http://192.168.1.62:18000`) - `SUPA_KEY`:Supabase service_role 或 anon key(用于 REST 写入) - `SUPA_USE_BEARER`(可选):是否附加 `Authorization: Bearer `,默认 `false`。 - 在一些自托管 Supabase/Kong(key-auth)环境中,**只需要** `apikey`;如果误加 Bearer 且 key 不是 JWT,可能出现 `PGRST301`("None of the keys was able to decode the JWT")。 - `WEBHOOK_SECRET`(可选):与第三方共享的 HMAC-SHA256 secret,用于校验 `X-Signature`(签名为 hex) - `WEBHOOK_REJECT_INVALID_SIGNATURE`(可选):若为 `true`,且配置了 `WEBHOOK_SECRET`,则验签失败会直接返回 HTTP 401(默认不拒绝,只记录)。 - `WEBHOOK_PORT`(可选):接收器监听端口,默认 `7201`(推荐用这个,便于与 push-server 共享同一份 `server/config.json`) - `PORT`(可选):接收器监听端口(兼容旧用法;若共享 `server/config.json` 且其中 `PORT=7301`,会导致端口冲突) 配置方式(推荐用配置文件,避免与其他服务端口冲突): - **同目录配置文件(推荐)**:在 `webhook-receiver.js` 同目录放置 `webhook.config.json`,启动时会自动读取。 - **显式指定配置文件**:设置 `CONFIG_FILE` / `CONFIG_PATH` 指向你的 `.env` 或 `.json`。 - **回退加载**:若未指定 `CONFIG_FILE` 且同目录无 `webhook.config.json`,会尝试读取 `server/.env` 与 `server/config.json`(由 `server/load-config.js` 负责)。 示例配置文件:仓库内提供 [server/webhook.config.json.example](server/webhook.config.json.example),你可以复制一份到本目录作为 `webhook.config.json` 使用。 启动(PowerShell): ```powershell node pages/mall/delivery/webhook-server/webhook-receiver.js ``` 推荐:使用同目录配置文件启动(PowerShell): ```powershell # 复制示例并填写真实 SUPA_KEY Copy-Item .\server\webhook.config.json.example .\pages\mall\delivery\webhook-server\webhook.config.json node pages/mall/delivery/webhook-server/webhook-receiver.js ``` 如果你使用显式 CONFIG_FILE: ```powershell $env:CONFIG_FILE=(Resolve-Path .\pages\mall\delivery\webhook-server\webhook.config.json) node pages/mall/delivery/webhook-server/webhook-receiver.js ``` 启动(Linux / macOS / WSL): ```bash export SUPA_URL='http://192.168.1.62:18000' export SUPA_KEY='your_service_role_key' export WEBHOOK_SECRET='your-secret' # optional node pages/mall/delivery/webhook-server/webhook-receiver.js ``` 也可以用配置文件(更适合长期运行): - `server/load-config.js` 会自动尝试加载:`server/.env`、`server/config.json`(以及 `CONFIG_FILE/CONFIG_PATH` 指定的文件),并把其中的键注入到 `process.env`。 - 因为接收器已在启动时 `require` 了该加载器,所以你只要把 `SUPA_URL`、`SUPA_KEY` 写进上述文件之一即可。 如果你不想与 `server/config.json` 共用 `PORT`(避免端口冲突),建议为 webhook 单独准备一个配置文件,然后用 `CONFIG_FILE` 指定: ```powershell # 复制示例文件并填写真实 SUPA_KEY: Copy-Item .\server\webhook.config.json.example .\server\webhook.config.json # 指定配置文件启动(不会影响 push-server 的配置): $env:CONFIG_FILE=(Resolve-Path .\server\webhook.config.json) node pages/mall/delivery/webhook-server/webhook-receiver.js ``` 示例:在 `server/.env` 中写入: ```env SUPA_URL=http://192.168.1.62:18000 SUPA_KEY=your_service_role_key WEBHOOK_SECRET=your-secret PORT=7201 ``` 测试(curl 模拟第三方推送): ```bash BODY='{"mailNo":"TEST_123","infoContent":"SENT","remark":"派送中","acceptTime":"2026-02-25 12:00:00","carrier":"YTO"}' TS=$(date -u +%Y-%m-%dT%H:%M:%SZ) # 如果启用了 WEBHOOK_SECRET,计算签名: SIG=$(printf "%s%s" "$BODY" "$TS" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" -hex | awk '{print $2}') curl -i -X POST http://localhost:7201/webhook/express/status \ -H "Content-Type: application/json" \ -H "X-Timestamp: $TS" \ -H "X-Client-Id: mock_carrier" \ -H "X-Signature: $SIG" \ -d "$BODY" ``` > 重要:签名计算必须使用**原始请求体文本**(raw body)。接收器也会使用 raw body 进行验签;不要用 JSON 对象 stringify 后的字符串替代。 健康检查: - `GET http://localhost:7201/health`(端口以 `PORT` 为准) 常见问题排查: - 返回 `{ ok:false, message:'waybill not found' }`:说明 webhook 已收到请求,但在 `platform_express_waybills` 中找不到 `tracking_no`(或 `order_no`)匹配的记录。 - 返回 `502 supabase unauthorized (check SUPA_KEY/SUPA_URL)`:说明当前 `SUPA_KEY` / `SUPA_URL` 无法通过 Supabase REST 鉴权(常见于 key 填错、已失效、URL 不对)。请换成 Supabase 控制台中的真实 `service_role` key,并重启接收器。 Windows 下保持“持续监听”(后台运行): > 只要 Node 进程还在,webhook 就会持续监听;如果你关闭终端/窗口或按 `Ctrl+C`,进程结束就不会再监听。 ```powershell # 后台启动并把日志写到文件(推荐) Start-Process node -ArgumentList 'pages/mall/delivery/webhook-server/webhook-receiver.js' \ -WorkingDirectory (Get-Location) \ -RedirectStandardOutput '.\webhook-receiver.log' \ -RedirectStandardError '.\webhook-receiver.err.log' \ -PassThru # 查看是否在监听(把 7201 换成你的 PORT) netstat -ano | findstr :7201 # 查看健康检查 Invoke-RestMethod -Uri 'http://localhost:7201/health' -Method GET | ConvertTo-Json ``` 停止服务(按 PID 结束进程): ```powershell # 先用 netstat 找到 LISTENING 的 PID,然后结束它 Stop-Process -Id ``` 依赖说明: - 建议使用 Node.js 18+(例如你当前的 Node.js 22),已内置 `fetch`,无需安装 `node-fetch`。 - 若使用更老的 Node 且没有 `fetch`,需要安装 `node-fetch`(并保持 CommonJS 兼容)。 预期:接口返回 200 JSON {ok:true}(若未找到对应运单会返回 {ok:false, message:'waybill not found'})。 验证写入(查看 Supabase): ```bash # 示例:列最近 5 条原始回文 curl -s -H "apikey: $SUPA_KEY" -H "Accept: application/json" \ "$SUPA_URL/rest/v1/platform_express_event_raw?select=*&order=received_at.desc&limit=5" | jq . # 查看最近轨迹事件 curl -s -H "apikey: $SUPA_KEY" -H "Accept: application/json" \ "$SUPA_URL/rest/v1/platform_express_tracking_events?select=*&order=created_at.desc&limit=5" | jq . # 如果你的环境已确认 Bearer 可用(不会触发 PGRST301),也可以额外加上: # -H "Authorization: Bearer $SUPA_KEY" ``` 与仓库中 Mock 实现的关系: - `pages/mall/delivery/test/mock-service.uts` 已包含写库逻辑(`pushWebhookData`、`bindShipment`、`runScenario`)。新接收器复用了同样的入库思路,但以 HTTP/REST 的形式对外暴露。 注意事项: - 本接收器通过 Supabase REST API 直接写表,使用 `SUPA_KEY` 时请确保权限与密钥安全(不要将 service_role key 公开到前端)。 - 如果你的 Supabase 接口部署在内网,请确保接收器能访问 `SUPA_URL`(网络/防火墙)。 - 若需要更严格的验签/重放检测/幂等,请告知,我可以把这些能力加入接收器(例如记录并比对 dedupe_key 或检查 X-Timestamp 时间窗口)。 下一步建议: - 若你要把第三方直接接到该接收器,请把 `WEBHOOK_SECRET` 与对方约定并启用验签。 - 若需要我加重放防护或返回 4xx/5xx 更精确的逻辑,也可继续实现。 文件位置: - [Webhook 接收器](pages/mall/delivery/webhook-server/webhook-receiver.js) 作者:自动生成(可手动调整)