190 lines
4.7 KiB
Markdown
190 lines
4.7 KiB
Markdown
# App Store 服务器通知接收接口
|
||
|
||
## 概述
|
||
|
||
本接口用于接收来自苹果App Store的服务器通知(App Store Server Notifications V2),处理用户订阅状态的变化,包括订阅、续订、过期、退款等事件。
|
||
|
||
## 接口地址
|
||
|
||
```
|
||
POST /api/users/app-store-notifications
|
||
```
|
||
|
||
## 配置要求
|
||
|
||
### 1. 在App Store Connect中配置
|
||
|
||
1. 登录 [App Store Connect](https://appstoreconnect.apple.com)
|
||
2. 选择你的应用
|
||
3. 在左侧菜单中选择 "App信息"
|
||
4. 滚动到 "App Store服务器通知" 部分
|
||
5. 设置生产环境URL:`https://your-domain.com/api/users/app-store-notifications`
|
||
6. 设置沙盒环境URL:`https://your-domain.com/api/users/app-store-notifications`
|
||
7. 选择 "Version 2" 通知格式
|
||
8. 保存设置
|
||
|
||
### 2. 环境变量配置
|
||
|
||
确保以下环境变量已正确设置:
|
||
|
||
```bash
|
||
# Apple相关配置
|
||
APPLE_BUNDLE_ID=com.yourcompany.yourapp
|
||
APPLE_KEY_ID=your_key_id
|
||
APPLE_ISSUER_ID=your_issuer_id
|
||
APPLE_PRIVATE_KEY_PATH=path/to/your/private/key.p8
|
||
APPLE_APP_SHARED_SECRET=your_shared_secret
|
||
```
|
||
|
||
## 请求格式
|
||
|
||
### 请求头
|
||
```
|
||
Content-Type: application/json
|
||
```
|
||
|
||
### 请求体
|
||
```json
|
||
{
|
||
"signedPayload": "eyJhbGciOiJFUzI1NiIsImtpZCI6IjEyMzQ1Njc4OTAiLCJ0eXAiOiJKV1QifQ..."
|
||
}
|
||
```
|
||
|
||
## 响应格式
|
||
|
||
### 成功响应
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "通知处理成功",
|
||
"data": {
|
||
"processed": true,
|
||
"notificationType": "SUBSCRIBED",
|
||
"notificationUUID": "12345678-1234-1234-1234-123456789012",
|
||
"userId": "user_12345",
|
||
"transactionId": "1000000123456789"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 错误响应
|
||
```json
|
||
{
|
||
"code": 500,
|
||
"message": "处理通知失败: 无法解码通知负载",
|
||
"data": {
|
||
"processed": false
|
||
}
|
||
}
|
||
```
|
||
|
||
## 支持的通知类型
|
||
|
||
### 1. SUBSCRIBED(订阅)
|
||
- **描述**: 用户首次订阅或重新订阅
|
||
- **处理**: 更新用户的订阅状态和到期时间
|
||
|
||
### 2. DID_RENEW(续订)
|
||
- **描述**: 订阅成功续订
|
||
- **处理**: 延长用户的订阅到期时间
|
||
|
||
### 3. EXPIRED(过期)
|
||
- **描述**: 订阅已过期
|
||
- **处理**: 可以发送邮件通知或降级用户权限
|
||
|
||
### 4. DID_FAIL_TO_RENEW(续订失败)
|
||
- **描述**: 订阅续订失败(通常是支付问题)
|
||
- **处理**: 发送付款提醒或进入宽限期
|
||
|
||
### 5. REFUND(退款)
|
||
- **描述**: 用户获得退款
|
||
- **处理**: 立即撤销用户的订阅权限
|
||
|
||
### 6. REVOKE(撤销)
|
||
- **描述**: 通过家庭共享获得的权限被撤销
|
||
- **处理**: 撤销用户的订阅权限
|
||
|
||
### 7. DID_CHANGE_RENEWAL_STATUS(续订状态变更)
|
||
- **描述**: 用户更改了自动续订设置
|
||
- **处理**: 记录用户的续订偏好
|
||
|
||
### 8. TEST(测试)
|
||
- **描述**: 测试通知
|
||
- **处理**: 仅记录日志,无特殊处理
|
||
|
||
## 安全考虑
|
||
|
||
### 1. 签名验证
|
||
- 接口会验证通知的JWS签名
|
||
- 确保通知来自苹果官方服务器
|
||
- 验证bundleId匹配
|
||
|
||
### 2. 重复处理
|
||
- 建议实现幂等性处理
|
||
- 根据notificationUUID去重
|
||
- 避免重复处理相同通知
|
||
|
||
### 3. 错误处理
|
||
- 对于无法处理的通知,返回适当的HTTP状态码
|
||
- 苹果会根据响应状态码决定是否重试
|
||
|
||
## 日志记录
|
||
|
||
接口会记录以下信息:
|
||
- 收到的通知类型和UUID
|
||
- 解码后的交易信息
|
||
- 处理结果和任何错误
|
||
- 用户ID和交易ID(如果可用)
|
||
|
||
## 测试
|
||
|
||
### 1. 使用App Store Connect测试
|
||
1. 在App Store Connect中请求测试通知
|
||
2. 检查服务器日志确认收到通知
|
||
3. 验证通知处理逻辑是否正确
|
||
|
||
### 2. 沙盒环境测试
|
||
1. 使用沙盒环境进行购买测试
|
||
2. 观察通知是否正确触发
|
||
3. 验证用户状态是否正确更新
|
||
|
||
## 故障排除
|
||
|
||
### 常见问题
|
||
|
||
1. **收不到通知**
|
||
- 检查App Store Connect中的URL配置
|
||
- 确保服务器可以从外网访问
|
||
- 检查防火墙设置
|
||
|
||
2. **通知解码失败**
|
||
- 验证私钥文件路径和格式
|
||
- 检查环境变量配置
|
||
- 确认bundleId匹配
|
||
|
||
3. **用户状态未更新**
|
||
- 检查appAccountToken是否正确设置
|
||
- 验证用户ID映射逻辑
|
||
- 查看数据库更新日志
|
||
|
||
### 日志查看
|
||
```bash
|
||
# 查看相关日志
|
||
grep "App Store" /path/to/your/logs/app.log
|
||
grep "processAppStoreNotification" /path/to/your/logs/app.log
|
||
```
|
||
|
||
## 扩展功能
|
||
|
||
可以根据业务需求扩展以下功能:
|
||
|
||
1. **邮件通知**: 在特定事件发生时发送邮件
|
||
2. **数据分析**: 收集订阅数据用于分析
|
||
3. **第三方集成**: 将事件发送到其他系统
|
||
4. **自定义业务逻辑**: 根据不同的通知类型执行特定操作
|
||
|
||
## 相关文档
|
||
|
||
- [App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications)
|
||
- [App Store Server API](https://developer.apple.com/documentation/appstoreserverapi)
|
||
- [StoreKit 2](https://developer.apple.com/documentation/storekit) |