本文详解如何在 Go Web 服务器中接收并解析 iOS(Swift)通过 NSData 序列化后 POST 的 JSON 数据,包括结构体定义、请求体读取、JSON 反序列化及 receipt 字段的 Base64 编码处理。
本文详解如何在 go web 服务器中接收并解析 ios(swift)通过 nsserialization 序列化后 post 的 json 数据,包括结构体定义、请求体读取、json 反序列化及 receipt 字段的 base64 编码处理。
在 iOS 端,你使用 NSJSONSerialization.dataWithJSONObject(...) 将包含 receipt(原始二进制数据)和 prod_id(字符串)的字典序列化为 JSON,并作为 HTTP 请求体发送至 Go 服务端。此时,receipt 在 JSON 中会被自动编码为 Base64 字符串(因为 NSData 在序列化时默认转为 Base64),而 prod_id 保持为普通字符串。
因此,Go 服务端需定义与之匹配的结构体,并使用 json.Unmarshal 解析请求体。关键在于:Go 不会自动将 JSON 中的 Base64 字符串还原为字节切片——你需要显式解码。以下是完整、安全的处理流程:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
1. 定义接收结构体(含 JSON 标签与类型适配)
type ReceiptRequest struct {
Receipt []byte `json:"receipt"` // Go 会自动将 JSON 中的 Base64 字符串解码为 []byte
ProdID string `json:"prod_id"`
}✅ 注意:Go 的 encoding/json 包对 []byte 类型有特殊支持——当 JSON 字段值为合法 Base64 字符串时,反序列化会自动调用 base64.StdEncoding.DecodeString 转为字节切片,无需手动处理。
2. 在 HTTP Handler 中解析请求
func validateReceiptHandler(w http.ResponseWriter, r *http.Request) {
// 读取请求体(务必检查 Content-Type)
if r.Header.Get("Content-Type") != "application/json" {
http.Error(w, "Content-Type must be application/json", http.StatusBadRequest)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusBadRequest)
return
}
defer r.Body.Close() // 防止资源泄漏
var req ReceiptRequest
if err := json.Unmarshal(body, &req); err != nil {
http.Error(w, "Invalid JSON format: "+err.Error(), http.StatusBadRequest)
return
}
// 此时 req.Receipt 已是原始 receipt 二进制数据([]byte)
// req.ProdID 是字符串,可直接使用
// 示例:Base64 编码 receipt(如需日志或转发)
encodedReceipt := base64.StdEncoding.EncodeToString(req.Receipt)
log.Printf("Received product ID: %s, receipt length: %d bytes (Base64: %s)",
req.ProdID, len(req.Receipt), encodedReceipt)
// 后续可调用 Apple IAP 验证 API 或本地校验逻辑...
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
}3. iOS 端注意事项(确保兼容性)
- receipt 必须是 NSData(Swift 中为 Data),且未被额外编码(如 UTF-8 字符串);
- 若 receipt 来自 appStoreReceiptURL,请确保读取的是原始二进制内容(非字符串);
- 推荐添加 request.HTTPHeaderField = ["Content-Type": "application/json"];
- 错误处理不可省略:optionalJson 为 nil 时应中断上传。
总结
- Go 的 json 包对 []byte 字段原生支持 Base64 自动编/解码,是处理二进制 payload 的最佳实践;
- 永远验证 Content-Type 并及时 Close() 请求体;
- 不要先 ioutil.ReadAll 再手动 Base64 编码整个 JSON——应先结构化解析,再对 Receipt 字段单独操作;
- 生产环境建议添加请求大小限制(如 http.MaxBytesReader)防止内存耗尽。
遵循以上模式,即可稳健、高效地完成 iOS → Go 的 receipt 验证链路。

















