# App Store 服务器通知收不到:V2 排查清单 > 收不到 App Store 服务器通知 V2?检查 URL、TLS 1.2、端口和 HTTP 200 回应,再让 Apple 发一条测试通知。 - Canonical page: https://obelisk.club/blog/app-store-server-notifications-not-arriving-zh - Author: Peter Zhang - Published: 2026-11-01 - Tags: app-store-connect, storekit, in-app-purchase, debugging, indie, 中文 App Store Server Notifications V2 到不了你的服务器时,别再猜了,直接问 Apple 发生了什么:调用 App Store Server API 的 **Request a Test Notification**,再用返回的令牌调用 **Get Test Notification Status**。返回结果会列出每一次发送尝试和结果,比如 `TLS_ISSUE`、`TIMED_OUT` 或 `UNSUCCESSFUL_HTTP_RESPONSE_CODE`,原因基本就清楚了。常见原因都写在 Apple 自己的配置页里:App Store Connect 里没填 URL(或只填了沙盒 URL)、服务器不支持 TLS 1.2 及以上、端口不是 443 也不在 1024 及以上、防火墙挡了 Apple 的 `17.0.0.0/8` 网段,或者回应的不是 HTTP 200 到 206。 ## Apple 发什么,期望你回什么 App Store 用 HTTP `POST` 发送每条通知,正文是 JSON。V2 的正文是 `responseBodyV2`,其中的 `signedPayload` 由 App Store 以 JWS 格式签名。你的服务器用状态码回应: - HTTP `200`,或 `200` 到 `206` 之间的任何状态码,表示成功。 - HTTP `40x` 或 `50x` 表示请 App Store 重试。其他状态码 Apple 都算失败。 - 不需要返回正文。 第一次发送没收到成功回应时,Apple 会对 V2 通知重试五次,分别在上一次尝试之后 1、12、24、48、72 小时。**只有正式环境会重试。** Apple 说沙盒环境只尝试发送一次。 V1 通知已弃用,Apple 要求改用 V2 端点。 ## 按这个顺序检查配置 1. **App Store Connect 里填了 URL。** 在 **App** 里选中应用,侧栏 General 下点 **App 信息**,找到 **App Store Server Notifications**。填写 **Production Server URL**,测试时再填 **Sandbox Server URL**,两个都选 **Version 2**。Apple 帮助页写的可操作角色是:Account Holder、Admin、App Manager 或 Marketing。 2. **清楚哪个 URL 收什么。** Apple 帮助页说,没填沙盒 URL 时,沙盒和正式环境的通知都会发到正式 URL;只填了沙盒 URL 时,正式环境不会发送任何通知。两个环境可以用同一个 URL。 3. **TLS 1.2 及以上。** Apple 写明服务器"must support the Transport Layer Security (TLS) 1.2 protocol or later"(必须支持 TLS 1.2 或更高版本)。`TLS_ISSUE` 这个结果也包括证书无法验证的情况。 4. **端口。** URL 里如果写了端口,必须是 `443`,或者大于等于 `1024`。 5. **防火墙。** 如果服务器只接受白名单 IP,加上 `17.0.0.0/8`。Apple 说这个网段同时适用于沙盒和正式环境。 6. **回应。** 收到请求就先回 `200`。`TIMED_OUT` 的说明是让你"check that your server isn't processing messages in line"(确认服务器没有在请求里同步处理消息),所以先把正文存下来,再另行处理。Apple 没有公开超时时间。 7. **你测试的是哪个环境。** 沙盒购买只发一次通知、不重试,发往沙盒 URL(没填沙盒 URL 则发往正式 URL)。 新保存的 URL 要多久开始收到通知,Apple 没说。 ## 怎么检查:测试通知、发送状态、历史记录 调用 App Store Server API 需要用 **In-App Purchase 密钥**签名的 JSON Web Token。密钥在 App Store Connect 的 **用户和访问 > 集成 > App 内购买项目** 里生成;Apple 只允许下载一次私钥。测沙盒 URL 用沙盒主机,测正式 URL 用正式主机。 **1. 请求一条 `TEST` 通知。** ```bash curl -X POST -H "Authorization: Bearer $JWT" \ https://api.storekit-sandbox.apple.com/inApps/v1/notifications/test # {"testNotificationToken": "..."} ``` 调用沙盒主机时,Apple 把 `TEST` 通知发到你的沙盒 URL;调用 `api.storekit.apple.com` 时,发到正式 URL。 **2. 看 Apple 记录了什么。** ```bash curl -H "Authorization: Bearer $JWT" \ https://api.storekit-sandbox.apple.com/inApps/v1/notifications/test/$TOKEN ``` 返回里有 `sendAttempts` 数组(最多六项:第一次尝试加最多五次重试),每项有 `attemptDate` 和 `sendAttemptResult`,另外还有 Apple 尝试发送的 `signedPayload`。一个令牌最长可查六个月。各结果的含义,按 Apple 的列表整理: | `sendAttemptResult` | Apple 的说明(节选) | 该查哪里 | |---|---|---| | `SUCCESS` | Apple 收到了成功回应。 | 回应之后你自己的处理代码。 | | `TLS_ISSUE` | 无法建立 TLS 会话,或证书无法验证。 | 证书链、TLS 1.2+。 | | `UNSUCCESSFUL_HTTP_RESPONSE_CODE` | 没收到 HTTP 200 回应。 | 鉴权中间件、路由、状态码。 | | `TIMED_OUT` | 超时前没收到回应。 | 先回应,后处理。 | | `NO_RESPONSE` | 没收到有效的 HTTP 回应。 | 服务器或代理。 | | `CIRCULAR_REDIRECT` | 重定向循环。 | 重定向规则(http 转 https、结尾斜杠)。 | | `PREMATURE_CLOSE` | 发送过程中连接被关闭。 | 代理、负载均衡。 | | `SOCKET_ISSUE` | 网络错误。 | DNS、防火墙、端口。 | | `INVALID_RESPONSE` | 回应无效。 | 服务器写出的回应。 | | `UNSUPPORTED_CHARSET` | Apple 不支持该字符集。 | 回应头。 | | `OTHER` | 其他错误。 | 以上全部。 | **3. 找回错过的真实通知。** **Get Notification History**(`POST /inApps/v1/notifications/history`)返回 Apple 尝试发送过的 V2 通知及其发送记录。`startDate` 和 `endDate` 用 UNIX 毫秒;加上 `"onlyFailures": true` 只看没送达的,包括还在重试中的。正式环境可查 180 天,沙盒 30 天,每次返回最多 20 条。 ```bash curl -X POST -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \ -d '{"startDate": 1761955200000, "endDate": 1762041600000, "onlyFailures": true}' \ https://api.storekit.apple.com/inApps/v1/notifications/history ``` Apple 提醒,历史记录反映的是通知发出那一刻的购买状态。要看当前状态,调用 Get All Subscription Statuses 或 Get Transaction History。 **4. 看通知内容。** 想知道一条通知里有什么,把 `signedPayload`(或整个正文)粘到 [App Store JWS 解码工具](/tools/app-store-jws-decoder) 里。Apple 给的步骤:把 JWS 拆成 header、payload、signature,对 payload 做 Base64URL 解码,得到通知类型和 `data`,再用同样方法解码 `signedTransactionInfo` 和 `signedRenewalInfo`。在服务器上,按 header 里 `alg` 指定的算法验证每个签名。 ## 常见问题 ### 正式环境能收到,沙盒收不到,为什么? 先确认沙盒 URL 已填写并选了 Version 2,再对沙盒主机调用 Request a Test Notification。记住沙盒只尝试一次,失败一次就不会再发;沙盒的 Get Notification History 可以往回查 30 天。 ### 测试通知能收到,真实通知收不到,怎么办? 对购买发生的那段时间调用 Get Notification History 并加上 `onlyFailures`。如果什么都没列出,说明那段时间 Apple 没尝试发送这类事件的通知,去对照 Apple 文档里该事件对应的通知类型。如果列出了发送记录,看 `sendAttemptResult` 就知道为什么失败。 ### 服务器明明收到了,Apple 还在一直重试,为什么? Apple 只把 `200` 到 `206` 算作成功。鉴权层返回的 `401`、一次重定向、或者回应太慢导致超时,都算失败;在正式环境,Apple 会在几天内最多重试五次。 ### 我配置的是 Version 1,能收到测试通知吗? 能。不管 URL 设的是 V1 还是 V2,Apple 都按 V2 格式发送 `TEST`。V1 已弃用,在沙盒里测好 V2 之后就切换过去。 ### 服务器宕机了一天,那些通知丢了吗? 正式环境下 Apple 会重试五次,分别在上一次尝试之后 1、12、24、48、72 小时,所以一天的宕机可能会被后面的重试补上。Get Notification History 也能返回最近 180 天的通知,可以把错过的取回来。 ## 参考资料 均于 2026 年 11 月 1 日阅读。 - [App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications),Apple Developer Documentation - [Enabling App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications/enabling-app-store-server-notifications),Apple Developer Documentation - [Receiving App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications/receiving-app-store-server-notifications),Apple Developer Documentation - [Responding to App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications/responding-to-app-store-server-notifications),Apple Developer Documentation - [responseBodyV2](https://developer.apple.com/documentation/appstoreservernotifications/responsebodyv2),Apple Developer Documentation - [Request a Test Notification](https://developer.apple.com/documentation/appstoreserverapi/request-a-test-notification)、[Get Test Notification Status](https://developer.apple.com/documentation/appstoreserverapi/get-test-notification-status)、[CheckTestNotificationResponse](https://developer.apple.com/documentation/appstoreserverapi/checktestnotificationresponse)、[sendAttemptResult](https://developer.apple.com/documentation/appstoreserverapi/sendattemptresult),App Store Server API - [Get Notification History](https://developer.apple.com/documentation/appstoreserverapi/get-notification-history)、[NotificationHistoryRequest](https://developer.apple.com/documentation/appstoreserverapi/notificationhistoryrequest)、[NotificationHistoryResponse](https://developer.apple.com/documentation/appstoreserverapi/notificationhistoryresponse),App Store Server API - [App Store Server API](https://developer.apple.com/documentation/appstoreserverapi),Apple Developer Documentation - [Creating API keys to authorize API requests](https://developer.apple.com/documentation/appstoreserverapi/creating-api-keys-to-authorize-api-requests),Apple Developer Documentation - [Enter server URLs for App Store Server Notifications](https://developer.apple.com/help/app-store-connect/configure-in-app-purchase-settings/enter-server-urls-for-app-store-server-notifications),App Store Connect 帮助 *Apple 的接口和限制会变化,具体以上面这些页面的当前内容为准。*