贝利信息

如何在 Go 中正确解析 JSON 并填充结构体字段

日期:2026-01-19 00:00 / 作者:心靈之曲

go 的 `encoding/json` 包仅能序列化和反序列化导出(首字母大写)的结构体字段;若字段为小写(未导出),json 解析将静默失败,导致结构体字段为空。

在 Go 中解析 JSON 时,一个常见却容易被忽视的陷阱是:结构体字段必须是导出字段(即首字母大写),否则 json.Unmarshal 或 json.NewDecoder.Decode 将无法为其赋值——即使不报错,字段也始终为空字符串、零值或 nil。

这是因为 Go 的 encoding/json 包基于反射(reflection)工作,而反射只能访问导出(public)字段。未导出字段(如 id string)对包外代码(包括标准库)不可见,因此 JSON 解析器会跳过它们,且不会返回错误。

以下是一个修复后的完整示例:

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

type RefreshTokenData struct {
    Id            string `json:"id"`
    IssuedAt      string `json:"issued_at"`     // 推荐使用驼峰命名,更符合 Go 风格
    Scope         string `json:"scope"`
    InstanceURL   string `json:"instance_url"`
    TokenType     string `json:"token_type"`
    RefreshToken  string `json:"refresh_token"`
    IDToken       string `json:"id_token"`      // 注意:原 JSON 含此字段,原结构体缺失
    Signature     string `json:"signature"`
    AccessToken   string `json:"access_token"`
}

func main() {
    tokenResp := `{
        "id": "https://google.com",
        "issued_at": "1423698767063",
        "scope": "full refresh_token",
        "instance_url": "https://na15.salesforce.com",
        "token_type": "Bearer",
        "refresh_token": "2os53__CCU5JX_yZXE",
        "id_token": "5jSH0Oqm7Q4fc0xkE9NOvW8cA13U",
        "signature": "/599EkGVIBsKPFRNkg+58wZ3Q7AFyclvIGvCrxVeyTo=",
        "access_token": "sadfasdfasdfasdfdsa"
    }`

    var tokenData RefreshTokenData
    if err := json.Unmarshal([]byte(tokenResp), &tokenData); err != nil {
        fmt.Printf("❌ JSON 解析失败: %v\n", err)
        return
    }

    fmt.Printf("✅ 成功解析:\n")
    fmt.Printf("- RefreshToken: %q\n", tokenData.RefreshToken)
    fmt.Printf("- AccessToken:  %q\n", tokenData.AccessToken)
    fmt.Printf("- IDToken:      %q\n", tokenData.IDToken)
}
✅ 输出示例:✅ 成功解析:- RefreshToken: "2os53__CCU5JX_yZXE"- AccessToken: "sadfasdfasdfasdfdsa"- IDToken: "5jSH0Oqm7Q4fc0xkE9NOvW8cA13U"

关键注意事项:

遵循以上原则,即可确保 Go 中 JSON 解析稳定、可靠、可维护。