欢迎,来自IP地址为:18.97.9.173 的朋友


JSON 格式数据渐渐成为网络应用数据交互的标准格式,无论是接收客户端发来的请求,还是向客户端返回响应,JSON 格式数据都被大量应用。对于 JSON 数据的编码和解码就成为一项基本技能。

本文将示例讲解如何使用 Go 语言来处理 JSON 数据(编码和解码)。

如何发送 JSON 数据(编码)

编码是指将数据从一种格式转换为另一种格式的过程。在计算和数据传输的背景下,编码通常涉及将数据转换为标准化格式,以便不同的系统或应用程序轻松存储、传输或处理。

可以将编码想象成打包行李箱准备旅行,将衣服(数据)打包到行李箱(编码格式)中,以便在目的地轻松运输(传输)和打开(解码)。

在 Go 语言中,JSON 编码就是将 Go 数据结构转换为 JSON 格式的过程。

在 JSON 编码的情况下,数据被转换为基于文本的格式,使用人类可读的字符来表示数据。这使得人类可以轻松阅读和理解数据,方便不同的系统可以轻松交换和处理数据。

对数据进行编码的一些常见原因包括:

  • 数据压缩:减小数据大小,使其更易于存储或传输
  • 数据安全:保护数据免受未经授权的访问或篡改
  • 数据兼容性:将数据转换为可由不同系统或应用程序读取和处理的格式
  • 数据传输:将数据转换为可通过网络或其他通信渠道轻松传输的格式

在 Go 语言中,可以使用”encoding/json”来对数据进行编码。

使用 Marshal 函数编码

Marshal 函数是 Go 语言中编码 JSON 数据最常用的方法。它以 Go 数据结构作为输入并返回 JSON 编码的字符串。

package main

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

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	person := Person{Name: "John", Age: 30}

	// Encoding - One step
	jsonStr, err := json.Marshal(person)
	if err != nil {
		os.Exit(1)
	}
	fmt.Println(string(jsonStr))
}

代码讲解如下:

引入的包

  • encoding/json:用于编码和解码 JSON 数据
  • fmt:用于打印输出
  • os:用于调用系统中断,异常退出

用户结构体

  • 定义了一个结构体 Person,包含 Name 和 Age 两个字段
  • 结构体标签(例如:`json:”age”`)用于指定 JSON 键名称

主函数

  • 首先创建一个 person 实例
  • 调用 Marshal 函数将结构体编码为 JSON数据,函数会返回编码后的 byte 切片以及一个错误
  • 如果函数执行成功,则可以将切片转换成字符串在控制台打印输出

使用 NewEncoder 函数

NewEncoder 函数用于将 JSON 数据编码到写入器,例如文件或网络连接。

package main

import (
	"encoding/json"
	"net/http"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func handler(w http.ResponseWriter, r *http.Request) {
	person := Person{Name: "John", Age: 30}

	// Encoding - 2 step . NewEncoder and Encode
	encoder := json.NewEncoder(w)

	err := encoder.Encode(person)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)

		return
	}
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

代码讲解如下:

  • handler 程序函数是一个 HTTP 处理程序,用于处理传入的 HTTP 请求
  • w http.ResponseWriter:w 是一个写入器,用于写入响应
  • r *http.Request:表示传入的请求
  • 创建了一个名为 person 的 Person 实例,并使用值 Name:”John”和 Age:30 对其进行了初始化
  • 使用 json.NewEncoder(w) 创建了一个 JSON 编码器,它将 JSON 输出写入响应编写器 w
  • 使用encoder.Encode(person) 将 person 结构编码为 JSON 并写入响应
  • 如果在编码过程中发生错误,则会将其作为 HTTP 错误响应发送回客户端,状态代码为 500 内部服务器错误

如何解析 JSON 数据(解码)

解码是指将数据从标准格式转换回其原始形式的过程。在计算和数据传输中,解码涉及获取编码数据并将其转换为特定系统或应用程序可以轻松理解和处理的格式。

可以将解码想象成旅行后打开行李箱。您将打包好的行李箱(编码数据)拿走并打开,将每个物品(数据)放回其原始位置,以便再次使用。

Go 语言中的JSON 解码是将 JSON 数据转换为 Go 数据结构的过程。

在 JSON 解码的情况下,基于文本的 JSON 数据将转换回其原始形式,例如 Go 数据结构(如结构体或切片),以便应用程序可以轻松访问和处理它。

解码数据的一些常见原因包括:

  • 数据提取:从较大的编码数据集中检索特定数据
  • 数据分析:将编码数据转换为易于分析或处理的格式
  • 数据存储:将编码数据转换为易于存储在数据库或文件系统中的格式
  • 数据可视化:将编码数据转换为易于可视化或显示的格式

解码本质上是编码的逆过程,它是许多数据处理流程中必不可少的步骤。

在 Golang 中,可以使用 encoding/json 包来解码 JSON 数据。

使用 Unmarshal 解码 JSON 数据

Unmarshal 函数是 Golang 中解码 JSON 数据最常用的方法。它以 JSON 编码的字符串和指向 Go 数据结构的指针为输入,解码中出现的错误做为返回值,解码成功,会将相应数据填充至对应的数据结构中。

package main

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

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	data := `{"Name": "John", "Age": 30}`
	jsonstr := []byte(data)

	var person Person
	// Decoding - One step
	err := json.Unmarshal(jsonstr, &person)
	if err != nil {
		os.Exit(1)
	}
	fmt.Println(person.Name, person.Age)
}

使用 NewDecoder 解码 JSON 数据

NewDecoder 函数可以用于解码来自读取器(例如文件或网络连接)的 JSON 数据。

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func handler(w http.ResponseWriter, r *http.Request) {

	decoder := json.NewDecoder(r.Body)

	var person Person
	err := decoder.Decode(&person)

	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	fmt.Println(person.Name)
	// Output: John
	fmt.Println(person.Age)
	// Output: 30
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

代码讲解如下:

  • handler 函数是一个 HTTP 处理程序,用于处理传入的 HTTP 请求
  • w http.ResponseWriter:用于写入响应
  • r *http.Request:表示传入的请求
  • decoder := json.NewDecoder(r.Body):创建一个从请求 Body 读取的新 JSON 解码器
  • person:声明一个 Person 类型的变量 person
  • err := decoder.Decode(&person):将请求 Body 中的 JSON 解码为 person 结构
  • 果在解码过程中发生错误,它会发送 HTTP 错误响应,并从函数返回
  • fmt.Println(person.Name): 打印 person 结构体的 Name 字段
  • fmt.Println(person.Age): 打印 person 结构体的 Age 字段

由于程序接收的是 HTTP 请求的 BODY 内容,想要看到执行效果,需要使用类似 Postman 之类的工具,向程序发送一个 BODY 包含 JSON 数据。

需要注意的是,如果请求的 JSON 数据键名与数据构中定义的不一致,则程序不会报错退出,只是不会将解码后的 JSON 值赋值至数据结构的对应字段;如果 JSON 数据中包含较数据结构多的键值对,则同样不会影响解码结果,函数会将与数据结构对应的键值对赋值对应字段,其余键值对会自动丢弃。

自定义 JSON 的编码和解码

在某些情况下,json.Marshal 和 json.Unmarshal 提供的默认 JSON 编码和解码功能可能不够用。例如,您可能需要自定义某些字段在 JSON 中的表示方式。这时 json.Marshaler 和 json.Unmarshaler 接口就派上用场了。

如何使用 JSON Marshaler 接口

json.Marshaler 接口允许您通过实现 MarshalJSON 方法来自定义类型的 JSON 编码。此方法返回 JSON 编码的字节切片和错误。

func (p Person) MarshalJSON() ([]byte, error) {
    type Alias Person
    return json.Marshal(&struct {
        Alias
        Age string `json:"age"`
    }{
        Alias: (Alias)(p),
        Age:   strconv.Itoa(p.Age) + " years",
    })
}

在此示例中,Age 字段在编码为 JSON 时被转换为带有“years”后缀的字符串。

如何使用 Unmarshaler 接口

json.Unmarshaler 接口允许我们通过实现 UnmarshalJSON 方法来自定义类型的 JSON 解码。此方法采用 JSON 编码的字节切片并返回错误。

func (p *Person) UnmarshalJSON(data []byte) error {
    type Alias Person
    aux := &struct {
        Alias
        Age string `json:"age"`
    }{Alias: (Alias)(*p)}

    if err := json.Unmarshal(data, &aux); err != nil {
        return err
    }

    ageStr := strings.TrimSuffix(aux.Age, " years")
    age, err := strconv.Atoi(ageStr)
    if err != nil {
        return err
    }

    p.Age = age
    p.Name = aux.Name
    return nil
}

在此示例中,Age 字段在从 JSON 解码时从带有“years”后缀的字符串转换为整数。

总之,掌握 JSON 编码和解码对于使用 Golang 开发 Web 应用程序至关重要。

通过了解 encoding/json 包中可用的不同方法,我们可以根据自己的特定需求选择最合适的方法。

Marshal 和 Unmarshal 函数为一般用途提供了简单性和灵活性,而 NewEncoder 和 NewDecoder 为大型数据集提供了高效的流式传输功能。

对于需要自定义 JSON 表示的场景,实现 json.Marshaler 和 json.Unmarshaler 接口可让您对编码和解码过程进行细粒度控制。

每种方法都有自己的优点和缺点,了解何时以及如何使用它们将使您能够在应用程序中有效地处理 JSON 数据。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注