在使用Python对接苹果支付(Apple In-App Purchase)时,验证收据(Receipt)是确保交易真实性的关键步骤。常见的一个技术问题是:**如何通过Python正确调用苹果的验证接口并处理收据验证结果?**
开发人员通常会遇到如下问题:如何构造请求体、如何处理苹果返回的JSON数据、如何判断收据是否有效、如何应对沙盒与生产环境的差异、以及如何安全地处理共享密钥(shared secret)等。此外,苹果官方文档对部分字段的解释较为模糊,例如`latest_receipt_info`和`pending_renewal_info`的解析方式,也常导致困惑。
本文将围绕Python实现苹果支付收据验证的完整流程,解答上述技术问题,并提供可复用的代码示例和最佳实践建议。
1条回答 默认 最新
白萝卜道士 2025-08-14 05:25关注使用Python验证苹果支付收据的完整指南
1. 苹果支付收据验证的基本流程
苹果支付(In-App Purchase)的收据验证是确保用户真实购买行为的关键步骤。苹果提供了两个验证接口:
- 生产环境:https://buy.itunes.apple.com/verifyReceipt
- 沙盒环境:https://sandbox.itunes.apple.com/verifyReceipt
验证流程如下:
import requests import json def verify_apple_receipt(receipt_data, shared_secret, is_sandbox=False): url = "https://sandbox.itunes.apple.com/verifyReceipt" if is_sandbox else "https://buy.itunes.apple.com/verifyReceipt" payload = { "receipt-data": receipt_data, "password": shared_secret } response = requests.post(url, data=json.dumps(payload)) return response.json()2. 构造请求体的关键字段
请求体必须包含两个核心字段:
字段名 说明 receipt-data 客户端传来的Base64编码的收据数据 password 应用的共享密钥(Shared Secret),用于订阅产品验证 注意:如果应用没有订阅产品,可以省略 password 字段。
3. 处理苹果返回的JSON数据
苹果返回的JSON结构包含多个关键字段:
{ "status": 0, "receipt": { "in_app": [ { "product_id": "com.example.product", "transaction_id": "1000000356891234", "purchase_date_ms": "1612139011000" } ] }, "latest_receipt_info": [...], "pending_renewal_info": [...] }status 为 0 表示验证成功,其他值表示错误。例如:
- 21002:receipt-data 格式错误
- 21007:收据来自沙盒环境,但请求发给了生产环境
4. 判断收据是否有效
除了检查 status 字段,还需要验证以下内容:
- 收据中的 product_id 是否与预期一致
- transaction_id 是否已处理过(防止重复消费)
- purchase_date_ms 是否在有效期内(如订阅产品)
示例代码片段:
def is_valid_receipt(data, expected_product_id): if data.get("status") != 0: return False in_app_receipts = data.get("receipt", {}).get("in_app", []) for receipt in in_app_receipts: if receipt.get("product_id") == expected_product_id: return True return False5. 沙盒与生产环境的差异处理
开发和测试阶段应使用沙盒环境进行验证。当遇到 status 为 21007 时,说明收据来自沙盒,但请求发给了生产接口。此时应切换 URL 重新验证。
自动切换示例逻辑:
def auto_retry_verify(receipt_data, shared_secret): result = verify_apple_receipt(receipt_data, shared_secret, is_sandbox=False) if result.get("status") == 21007: result = verify_apple_receipt(receipt_data, shared_secret, is_sandbox=True) return result6. 安全处理共享密钥(Shared Secret)
Shared Secret 是用于订阅产品验证的关键字段,必须安全存储。建议:
- 不要硬编码在代码中,应使用配置文件或环境变量
- 在生产环境中使用密钥管理系统(如AWS Secrets Manager)
获取 Shared Secret 的步骤:
- 登录 App Store Connect
- 进入【我的App】→【App特定密码】→【Apple ID和密码】→【共享密钥】
- 生成或查看现有的 Shared Secret
7. 解析 latest_receipt_info 和 pending_renewal_info
这两个字段用于处理订阅产品状态:
latest_receipt_info:最新的收据信息,适用于自动续订订阅pending_renewal_info:订阅的续订状态信息,如是否取消、是否自动续订等
示例解析逻辑:
def parse_latest_receipt_info(data): latest_info = data.get("latest_receipt_info", []) for receipt in latest_info: print(f"Product ID: {receipt.get('product_id')}") print(f"Expires Date: {receipt.get('expires_date_ms')}")8. 完整流程图
graph TD A[客户端提交收据] --> B{是否沙盒环境?} B -->|是| C[调用沙盒验证接口] B -->|否| D[调用生产验证接口] C --> E[处理返回JSON] D --> E E --> F{status是否为0?} F -->|否| G[处理错误码] F -->|是| H[解析in_app数据] H --> I[验证product_id和transaction_id] G --> J[尝试切换环境重新验证] J --> K[返回最终结果]本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报