Golang中JSON响应包含转义双引号的问题
Golang中JSON响应包含转义双引号的问题 问题描述: curl 命令返回的数据中包含转义的双引号,如下所示
curl -X GET http://test.com/api/appointment
{"Title":"OK","status":200,"records":2,"data":"[{\"id\":14,\"start\":\"2022-07-03T18:15:00Z\"}]
期望的输出是不带转义双引号的 {“Title”:“OK”,“status”:200,“records”:2,“data”:"[{“id”:14,“start”:“2022-07-03T18:15:00Z”}]
现在来解释程序逻辑。
需求是使用 gorm 检索数据库记录,并使用 json.NewEncoder(w).Encode 以 JSON 格式作为 API 响应发送回客户端。为此设计了以下结构体,其中 ApiResponse 结构体用于保存数据库查询结果(“Data”)以及元数据,如标题、状态和记录数。Appointment 结构体用于保存检索到的数据库记录,这些记录随后将嵌入到 API 响应中。由于我对不同的数据库表使用不同的结构体,检索到的数据库记录将存储在相应的结构体中,然后序列化为字节,再转换为字符串。最后,写回 http writer。
以下结构体用于构建 API 响应。
type ApiResponse struct {
Title string `json:"Title"`
Status uint `json:"status"`
Records int64 `json:"records"`
Data string `json:"data"`
}
以下结构体保存从数据库检索到的记录。
type Appointment struct {
Id uint `json:"id"`
Name string `json:"name"`
Start time.Time `json:"start"`
....SKIPPING THE REST....
}
// Appointment 是一个结构体,用于保存使用 gorm 检索到的数据库记录 // 将 appointment 序列化为 []byte,以便稍后转换为字符串。
data, _ := json.Marshal(appointment)
records := string(data)
// 将响应写回客户端
json.NewEncoder(w).Encode(ApiResponse{Title: "OK", Status: http.StatusOK, Records: utils.RowsAffected, Data: records })
除了输出中带有转义的双引号外,这完全符合我的需求。
"[{\"id\":14,\"start\":\"2022-07-03T18:15:00Z\"}]
请帮我找出那一两行代码,能够以最优的方式移除输出中的 \。
更多关于Golang中JSON响应包含转义双引号的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
不,因为那样不会是有效的JSON。
更多关于Golang中JSON响应包含转义双引号的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
如果引号没有被转义,那么JSON就是无效的。
Data 是一个字符串,而不是数组,因此其中的每个引号都需要被转义。
谢谢。但我正在寻找一种解决方案,以生成不带转义双引号的JSON字符串。在我的情况下,如何实现这一点。有没有办法在使用 json.NewEncoder(w).Encode 时实现以下JSON。
{"Title":"OK","status":200,"records":2,"data":"[{"id":14,"start":"2022-07-03T18:15:00Z"}]}
问题在于你的 Data 属性是一个字符串,而这个字符串恰好包含了 JSON 数据。因此,Go 正确地转义了该字符串中的引号。将你的结构体修改为包含一个子结构体数组,而不是一个字符串,如下所示:
package main
import (
"encoding/json"
"net/http"
"os"
"time"
)
type Appointment struct {
Id uint `json:"id"`
Name string `json:"name"`
Start time.Time `json:"start"`
}
type ApiResponse struct {
Title string `json:"Title"`
Status uint `json:"status"`
Records int64 `json:"records"`
Data []Appointment `json:"data"`
}
func main() {
appts := []Appointment{{1, "Apt Name", time.Now()}}
resp := ApiResponse{Title: "OK", Status: http.StatusOK, Records: 23, Data: appts}
json.NewEncoder(os.Stdout).Encode(resp)
}
… 这将产生以下输出:
{“Title”:“OK”,“status”:200,“records”:23,“data”:[{“id”:1,“name”:“Apt Name”,“start”:“2009-11-10T23:00:00Z”}]}
你可以在 Playground 中亲自运行它:Go Playground - The Go Programming Language
再次感谢您抽出时间。但这里的 Data 不是一个单一的结构体。它是一个通用的容器,应该容纳不同结构体的数据,例如客户、预约、员工。因此需要一个灵活的数据类型,比如字符串,以便在将这些结构体作为 API 响应发送之前将其转换为字符串。
//Struct for Appoinment
type Appointment struct {
Id uint `json:"id"`
Name string `json:"name"`
Start time.Time `json:"start"`
}
//Struct for Customers
type Customers struct {
Id unit `json:"id"`
Name string `json:"name"`
Phone string `json:"phone"`
DOB time `json:"dob"`
}
//Struct for Employees
type Employee struct {
Id unit `json:"id"`
Name string `json:"name"`
Phone string `json:"phone"`
Designation string `json:"designation"`
}
预期的 API 请求和响应 curl -X GET http://test.com/api/appointment {“Title”:“OK”,“status”:200,“records”:1,“data”:"[{“id”:14,“start”:“2022-07-03T18:15:00Z”}]
curl -X GET http://test.com/api/customers {“Title”:“OK”,“status”:200,“records”:1,“data”:"[{“id”:14,“name”:“John", “Phone”:+810000000", “11-11-11”}] & 员工的 curl 请求
虽然可以定义不同的 API 响应结构体,但这似乎效率不高。是否有更好的实现方式?
问题在于你将已经序列化为JSON字符串的数据再次作为字符串字段进行JSON编码,导致了双重编码。Data字段应该是[]Appointment类型,而不是字符串类型。
修改ApiResponse结构体:
type ApiResponse struct {
Title string `json:"Title"`
Status uint `json:"status"`
Records int64 `json:"records"`
Data []Appointment `json:"data"` // 直接使用结构体切片
}
然后直接传入appointment切片:
// 假设appointments是[]Appointment类型
json.NewEncoder(w).Encode(ApiResponse{
Title: "OK",
Status: http.StatusOK,
Records: utils.RowsAffected,
Data: appointments, // 直接传入结构体切片
})
如果你确实需要保持Data字段为字符串类型(不推荐),可以在编码前使用json.RawMessage:
type ApiResponse struct {
Title string `json:"Title"`
Status uint `json:"status"`
Records int64 `json:"records"`
Data json.RawMessage `json:"data"`
}
// 使用方式
data, _ := json.Marshal(appointments)
json.NewEncoder(w).Encode(ApiResponse{
Title: "OK",
Status: http.StatusOK,
Records: utils.RowsAffected,
Data: data,
})
推荐使用第一种方案,让JSON编码器一次性处理所有数据,避免双重编码问题。


