Golang中如何处理JSON解析出现的垃圾值?
Golang中如何处理JSON解析出现的垃圾值? 这是期望的结果:DB Fiddle - SQL 数据库游乐场

PGAdmin 也有类似的结果:

但从 Go 程序获取时,它却用垃圾值替代了 JSON 值:
[{“status_id”:0,“val”:“IkFrdGl2Ig==”},{“status_id”:1,“val”:“IkluYWt0aXYi”}]
查询语句:
WITH list AS
(SELECT status_id, json_array_elements(lang) as row FROM status)
SELECT status_id, row -> 'val' as val FROM list
WHERE row ->> 'key' = $1
Go 代码:
// query to return a list with status languages
func getlang(query string, val string) interface{} {
if len(query) > 0 {
var list []map[string]interface{}
rows, err := db.Queryx(query, val)
if err != nil {
log("no records")
}
defer rows.Close()
for rows.Next() {
row := make(map[string]interface{})
err = rows.MapScan(row)
if err != nil {
log(err.Error())
}
list = append(list, row)
}
rows.Close()
if len(list) == 0 {
return ("norec")
}
return list
}
return nil
}
查询在 Go 环境外运行正常,但在 Go 中却用垃圾值替换了实际值? 无论我是否使用占位符,结果都一样。 我到底做错了什么?
更多关于Golang中如何处理JSON解析出现的垃圾值?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我完全明白了你的意思。你让我理解起来容易多了。
更多关于Golang中如何处理JSON解析出现的垃圾值?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Sibert:
其他查询未使用JSON。
Sibert:
以及为什么只有一个JSON列
其他内容是否也未使用JSON,还是所有其他JSON都“正常”?
NobbZ:
没有其他东西在使用 JSON 吗?
这是我的第一个 JSON 列。其他列使用的是“普通”列。而且只有 JSON 列不是 UTF-8 编码。
你还没有展示任何其他查询,也没有提供相关表格和列的详细信息。
不过,从“PGAdmin”的截图来看,val 列似乎是一个 JSON 列。不确定其他“能工作”的东西是什么类型。
您使用哪种数据库驱动?它原生支持JSON列吗?为什么您要为纯字符串使用JSON列?
您如何将数据库查询结果转换为分享的JSON?如果使用 fmt.Printf("%#v", list) 直接检查查询结果,它看起来是什么样子?
后者在README中提到它处于维护模式,但其描述读起来更像是为了支持GitHub - jackc/pgx: PostgreSQL driver and toolkit for Go而进行的自我贬低,而后者在其README中明确提到了对JSON和JSONB的支持。
我找到了一个解决方案:
不使用 “JSON 对象”
row -> 'val'(意为 “Active”)
我使用了 “值”
row ->> ''val''(意为 Active)
问题依然存在。为什么 Go 不能像 dbfiddle 和 PGAdmin 那样处理带有 UTF-8 的对象?
这就是我问你使用哪个驱动以及它是否支持JSON列的原因。
从其他语言中我了解到,对JSON列的支持通常是不完整的。例如,Elixir的ecto只支持JSON列中的映射和数组,并且值必须是同构类型的。
// 代码示例(如有)
Sibert:
[{“status_id”:0,“val”:“IkFrdGl2Ig==”},{“status_id”:1,“val”:“IkluYWt0aXYi”}]
这不是“乱码”:
$ base64 --decode <<< IkFrdGl2Ig==
"Aktiv"
$ base64 --decode <<< IkluYWt0aXYi
"Inaktiv"
NobbZ:
$ base64 --decode <<< "IkFrdGl2Ig==" "Aktiv" $ base64 --decode <<< "IkluYWt0aXYi" "Inaktiv"%
为什么我只需要解码“val”?而不是查询结果的其他部分?
还有,为什么其他所有查询都不需要解码,唯独这个需要?
NobbZ:
你还没有展示任何其他查询
其他查询未使用JSON。
你也没有展示有关相关表和列的任何详细信息。

但问题仍然存在:在哪里以及如何解码,以及为什么只有一个JSON列?所有其他列都是正确的UTF-8编码。
@Sibert 和 @niamul21 关于驱动问题的问答是正确的答案,但如果你想在拥有 sqlx 结构体扫描功能的同时,又能获得原生级别的 pgx 支持,这里可能遗漏了一个很好的建议。
在这种情况下,使用 lib/pq 配合 sqlx 意味着你没有使用原生的 PostgreSQL 类型,并且所有内容都以文本形式传递给数据库。pgx 库支持所有 PostgreSQL 类型,性能可能更好,能获得安全更新(因为它不像你正在使用的仓库那样已归档),最后,如果你想要 sqlx 的功能(这是一个很好的库,但它只使用数据库接口,无法使用原生接口),那么你或许可以转向使用 scany:https://github.com/georgysavva/scany
NobbZ:
这就是我问你使用哪个驱动以及它是否支持JSON列的原因。
GitHub - jmoiron/sqlx: general purpose extensions to golang’s database/sql
general purpose extensions to golang’s database/sql - GitHub - jmoiron/sqlx: general purpose extensions to golang’s database/sql
GitHub - lib/pq: Pure Go Postgres driver for database/sql
Pure Go Postgres driver for database/sql. Contribute to lib/pq development by creating an account on GitHub.
我怎么知道这些驱动是否支持JSON?
问题出在数据库返回的JSON值被Base64编码了。从你展示的PGAdmin结果可以看出,val字段包含的是Base64编码的字符串,但在Go中直接解析时没有进行解码。
在你的例子中:
"IkFrdGl2Ig=="解码后是"Aktiv""IkluYWt0aXYi"解码后是"Inaktiv"
你需要对从数据库获取的val字段进行Base64解码。以下是修正后的代码:
import (
"encoding/base64"
"encoding/json"
"database/sql"
"github.com/jmoiron/sqlx"
)
func getlang(query string, val string) interface{} {
if len(query) > 0 {
type Row struct {
StatusID int `db:"status_id"`
Val string `db:"val"`
}
var rows []Row
err := db.Select(&rows, query, val)
if err != nil {
log("no records or error: " + err.Error())
return "norec"
}
if len(rows) == 0 {
return "norec"
}
// 解码Base64并构建结果
var result []map[string]interface{}
for _, row := range rows {
decodedBytes, err := base64.StdEncoding.DecodeString(row.Val)
if err != nil {
log("base64 decode error: " + err.Error())
continue
}
// 去除可能的JSON引号
decodedStr := string(decodedBytes)
if len(decodedStr) >= 2 && decodedStr[0] == '"' && decodedStr[len(decodedStr)-1] == '"' {
decodedStr = decodedStr[1 : len(decodedStr)-1]
}
result = append(result, map[string]interface{}{
"status_id": row.StatusID,
"val": decodedStr,
})
}
return result
}
return nil
}
或者,如果你需要保持原始的数据结构,但解码val字段:
func getlang(query string, val string) interface{} {
if len(query) > 0 {
var list []map[string]interface{}
rows, err := db.Queryx(query, val)
if err != nil {
log("no records")
return "norec"
}
defer rows.Close()
for rows.Next() {
row := make(map[string]interface{})
err = rows.MapScan(row)
if err != nil {
log(err.Error())
continue
}
// 解码Base64的val字段
if valStr, ok := row["val"].(string); ok {
decodedBytes, err := base64.StdEncoding.DecodeString(valStr)
if err == nil {
decodedStr := string(decodedBytes)
// 去除JSON字符串的引号
if len(decodedStr) >= 2 && decodedStr[0] == '"' && decodedStr[len(decodedStr)-1] == '"' {
decodedStr = decodedStr[1 : len(decodedStr)-1]
}
row["val"] = decodedStr
}
}
list = append(list, row)
}
if len(list) == 0 {
return "norec"
}
return list
}
return nil
}
问题的根源是数据库中的JSON值被存储为Base64编码的字符串。"IkFrdGl2Ig=="是"Aktiv"的Base64编码,"IkluYWt0aXYi"是"Inaktiv"的Base64编码。Go代码需要显式解码这些值才能得到正确的字符串内容。

