0

0

Go语言中实现JSON字段选择性读写:策略与实践

心靈之曲

心靈之曲

发布时间:2025-10-29 14:11:23

|

806人浏览过

|

来源于php中文网

原创

Go语言中实现JSON字段选择性读写:策略与实践

本文探讨了在go语言中处理json数据时,如何实现特定结构体字段只进行反序列化(读取)而不进行序列化(写入)的需求。通过采用结构体分离的策略,将完整数据模型与对外暴露的数据模型区分开来,可以优雅地解决json:"-"标签无法满足的场景,从而有效管理敏感数据或优化api响应。

在Go语言的Web服务开发中,我们经常需要将结构体(Struct)与JSON数据进行相互转换。有时,我们会遇到这样的需求:某个字段(例如用户密码的哈希值PasswordHash)在从JSON反序列化(Unmarshal)时需要被读取以完成内部逻辑,但在序列化(Marshal)为JSON响应时,出于安全或隐私考虑,该字段不应被写入。

传统JSON标签的局限性

Go语言的encoding/json包提供了强大的JSON标签(json:"fieldName")来控制字段的序列化和反序列化行为。其中,json:"-"标签常用于忽略某个字段,使其在JSON转换过程中完全不参与。

考虑以下User结构体:

type User struct {
    UserName     string   // 必须唯一
    Projects     []string // 用户有权访问的项目集合
    PasswordHash string   `json:"-"` // 用户密码的哈希值,标记为不序列化
    IsAdmin      bool     // 用户是否为管理员
}

如果我们将PasswordHash字段标记为json:"-",它确实会在序列化时被忽略。然而,问题在于这个标签也会导致该字段在反序列化时被忽略。这意味着,如果我们从外部JSON数据中读取一个包含PasswordHash的User对象,PasswordHash字段将无法被正确解析到结构体中,这与我们“只读不写”的需求相悖。

立即学习go语言免费学习笔记(深入)”;

示例反序列化代码:

import "encoding/json"

// ... 假设 content 是包含 PasswordHash 的 JSON 字节切片
var user User
err := json.Unmarshal(content, &user)
// 此时,如果 PasswordHash 字段带有 `json:"-"`,它将不会被 unmarshal 到 user.PasswordHash

示例序列化代码:

import (
    "bytes"
    "encoding/json"
)

// ... 假设 user 已经被填充
userBytes, _ := json.Marshal(user)
var respBuffer bytes.Buffer
json.Indent(&respBuffer, userBytes, "", "   ")
// respBuffer 现在包含序列化后的 user 数据,PasswordHash 字段会被忽略

显然,json:"-"标签无法满足我们对字段进行选择性读写的需求。

解决方案:结构体分离策略

为了实现JSON字段的只读不写,一种简洁且推荐的策略是根据不同的数据上下文(内部完整模型 vs. 外部API响应模型)定义不同的结构体。这种方法将语义上不同的对象在代码中也进行分离,从而清晰地管理数据的输入和输出视图。

剪映
剪映

一款全能易用的桌面端剪辑软件

下载

具体实现步骤如下:

  1. 定义外部可见结构体(UserInfo):这个结构体只包含那些可以被序列化(写入)到JSON响应中的字段。
  2. 定义内部完整结构体(User):这个结构体包含所有字段,包括那些只用于内部处理(如PasswordHash)的字段。通过内嵌(Embedding)外部可见结构体,可以重用字段定义。

修改后的结构体定义如下:

type UserInfo struct {
    UserName string   // 必须唯一
    Projects []string // 用户有权访问的项目集合
    IsAdmin  bool     // 用户是否为管理员
}

type User struct {
    UserInfo // 内嵌 UserInfo,包含所有对外可见字段

    // A hash of the password for this user
    PasswordHash string // 密码哈希,此字段不带 json 标签,默认参与读写
}

现在,UserInfo代表了用户信息的公共部分,而User则包含了所有内部管理所需的字段,包括敏感的PasswordHash。

实现选择性读写

有了这两个结构体,我们可以轻松实现字段的选择性读写:

反序列化(读取)

当从外部JSON数据读取用户对象时,我们使用完整的User结构体进行反序列化。由于PasswordHash字段在User结构体中没有json:"-"标签,它将正常参与反序列化过程。

import "encoding/json"

// 假设 content 是包含所有字段(包括 PasswordHash)的 JSON 字节切片
var user User
content := []byte(`{"UserName":"alice","Projects":["proj1","proj2"],"PasswordHash":"$2a$10$xyz","IsAdmin":true}`)
err := json.Unmarshal(content, &user)
if err != nil {
    // 处理错误
    panic(err)
}
// 此时,user.UserName, user.Projects, user.IsAdmin, 和 user.PasswordHash 都已被正确填充
fmt.Printf("Deserialized User: %+v\n", user)
// Output: Deserialized User: {UserInfo:{UserName:alice Projects:[proj1 proj2] IsAdmin:true} PasswordHash:$2a$10$xyz}

序列化(写入)

当需要将用户对象序列化为JSON响应时,我们只序列化User结构体中的UserInfo部分。这样,PasswordHash字段就会被自然地排除在外。

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

// 假设 user 已经被填充,例如从数据库加载或刚刚反序列化
user := User{
    UserInfo: UserInfo{
        UserName: "alice",
        Projects: []string{"proj1", "proj2"},
        IsAdmin:  true,
    },
    PasswordHash: "$2a$10$xyz", // 内部字段
}

// 序列化时,只使用 user.UserInfo
userBytes, err := json.Marshal(user.UserInfo)
if err != nil {
    // 处理错误
    panic(err)
}

var respBuffer bytes.Buffer
json.Indent(&respBuffer, userBytes, "", "   ")
fmt.Println("Serialized UserInfo for response:")
fmt.Println(respBuffer.String())

// Output:
// Serialized UserInfo for response:
// {
//    "UserName": "alice",
//    "Projects": [
//       "proj1",
//       "proj2"
//    ],
//    "IsAdmin": true
// }

通过这种方式,我们成功实现了PasswordHash字段在反序列化时被读取,而在序列化时被忽略的目的。

优点与注意事项

  • 清晰的职责分离:UserInfo明确表示对外暴露的数据视图,User则表示内部完整的数据模型,代码可读性和可维护性更高。
  • 灵活性:如果需要不同的API响应视图(例如,管理员视图包含更多信息,普通用户视图包含较少信息),可以轻松创建更多的UserView结构体。
  • 避免冗余:通过结构体内嵌,UserInfo的字段定义无需在User中重复。
  • 类型安全:编译时检查确保了正确的数据结构被使用。

注意事项: 虽然结构体分离是解决此问题的优雅方法,但在某些复杂场景下,例如字段选择性非常动态,或者需要对序列化/反序列化过程进行更精细的控制时,可能需要考虑实现json.Marshaler和json.Unmarshaler接口来自定义JSON转换逻辑。然而,对于本文提出的“只读不写”特定需求,结构体分离通常是更简单、更易于理解和维护的方案。

总结

在Go语言中,当遇到JSON字段需要只进行反序列化而不进行序列化的场景时,直接使用json:"-"标签是无效的。通过定义不同的结构体来代表数据的不同视图(内部完整模型和外部暴露模型),我们可以有效地管理数据流,确保敏感信息不会被意外序列化,同时保持反序列化功能的完整性。这种结构体分离的策略不仅解决了技术问题,也提升了代码的清晰度和可维护性。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

420

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

536

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

312

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

77

2025.09.10

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

240

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

192

2025.07.04

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

539

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

21

2025.12.22

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.6万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号