作者:matrix
发布时间:2024-12-24
分类:Golang
无意把除数为0的计算放了进来,既然没有发现panic,页面却显示空白。看起来像是没有被全局recover捕获~
gin 控制台显示
Error #01: json: unsupported value: NaN
排查
断点调试下发现json处理的问题,error被push到gin的c.Error里面,gin被判定为私有类型错误,所以没有panic
~/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go
func (c *Context) Render(code int, r render.Render) {
c.Status(code)
if !bodyAllowedForStatus(code) {
r.WriteContentType(c.Writer)
c.Writer.WriteHeaderNow()
return
}
if err := r.Render(c.Writer); err != nil {
// Pushing error to c.Errors
_ = c.Error(err)
c.Abort()
}
}
r.Render(c.Writer)
内部会json序列化,error被返回到r.Render。这个错误信息就直接给了上下文的c.Error(err)
原因
Json序列化时存在math.Nan
特殊浮点型数据会导response失败,
c.JSON
没有任何返回也就是空白页面显示了。
测试
func main() {
data := map[string]interface{}{
"name": "123",
"name_nan": math.NaN(), // json: unsupported value: NaN
// "name_inf": math.Inf(1), // json: unsupported value: +Inf
// "name_inf": math.Inf(-1), // json: unsupported value: -Inf
}
a, err := json.Marshal(data)
fmt.Println(a, err)
}
像NaN
这种其他特殊意义值 Inf
都回导致 JSON 序列化异常
解决办法
gin中添加错误处理中间件
func ErrorHandler() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next() // 继续执行请求处理链
//中间件处理完成后进行错误收集
if len(c.Errors) > 0 {
// 迭代错误并处理
for _, err := range c.Errors {
c.JSON(http.StatusInternalServerError, gin.H{
"code": http.StatusInternalServerError,
"message": err.Error(),
"data": nil,
})
c.Abort()
return
}
}
}
}
其他办法就是自行实现JSON序列化操作或者判断NaN
、Inf
数据
参考:
https://blog.axiaoxin.com/post/2021-11-21-Golang-%E8%BF%90%E8%A1%8C%E6%97%B6%E9%99%A4%E6%95%B0%E4%B8%BA-0-%E8%BF%94%E5%9B%9E-inf/
https://blog.csdn.net/qq_36268452/article/details/124809417
https://blog.csdn.net/qq_40227117/article/details/122186916
作者:matrix
发布时间:2023-10-18
分类:Golang
json Merge Patch,是一个Internet Engineering Task Force(IETF)标准。基本思想是,你有一个原始的json对象,然后根据提供的“补丁”JSON对象,最终生成原始JSON对象需要修改的结果。这种机制适用于部分更新(也称为PATCH更新)的场景。
例子
原始对象:
{
"Account": "old_account",
"Name": "old_name",
"Avatar": "old_avatar"
}
补丁对象(patch object):
{
"Account": "new_account",
"Name": null
}
应用补丁对象后的待更新数据(PATCH更新):
{
"Account": "new_account",
"Avatar": "old_avatar"
}
简单来说,补丁对象(patch object)描述了以下几种修改:
golang使用
使用实现IETF标准的JSON Merge Patch依赖库 json-patch
go get -u github.com/evanphx/json-patch
// JOSN PATCH
// dst 原始对象
// patch 补丁对象
// return 将补丁应用到原始对象
func MergePatch(dst, patch interface{}) error {
// 序列化目标(原始)结构体到JSON
dstJSON, err := json.Marshal(dst)
if err != nil {
return err
}
// 序列化补丁结构体到JSON,这个补丁描述了如何修改目标(原始)对象
patchJSON, err := json.Marshal(patch)
if err != nil {
return err
}
// 使用补丁合并目标(原始)对象
mergedJSON, err := jsonpatch.MergePatch(dstJSON, patchJSON)
if err != nil {
return err
}
// 反序列化合并后的JSON回到目标(原始)结构体
return json.Unmarshal(mergedJSON, dst)
}
调用:
if err := MergePatch(&originJSON, &patchJSON); err != nil {
u.JSONResponseError(ctx, err)
return
}
// originJSON 就是应用过补丁的最新原始结构数据
参考:
https://datatracker.ietf.org/doc/html/rfc7396
作者:matrix
发布时间:2014-09-04
分类:零零星星
php的json_decode函数用来解析json数据很方便,但是有时候却解析不了。
究其原因找到如下可能性:
1.键名没有用双引号括起来
['name':n,'age',a]
[name:n,age,a]
这两个都不能解析
2.出现多余逗号
['name':n,'age',a,]
###3.有些转义不支持
数据中出现\x26这样的会失败,有时候\'都无法解析。
用stripslashes()去掉转义即可!
4.json不支持gbk编码
iconv('GBK', 'UTF-8', $json_data);//使用iconv()函数将GBK转到UTF-8编码
json数据解析前用检测工具测试一下较好:http://www.bejson.com/
150515添加
/*
格式化错误的json数据,使其能被json_decode()解析
不支持健名有中文、引号、花括号、冒号
不支持健指有冒号
*/
function format_ErrorJson($data,$quotes_key=false)
{
$con = str_replace('\'','"',$data);//替换单引号为双引号
$con = str_replace(array('\\"'),array('<|YH|>'),$con);//替换
$con = preg_replace('/(\w+):[ {]?((?<YinHao>"?).*?\k<YinHao>[,}]?)/is', '"$1": $2',$con );//若键名没有双引号则添加
if($quotes_key)
{
$con = preg_replace('/("\w+"): ?([^"\s]+)([,}])[\s]?/is', '$1: "$2"$3',$con );//给键值添加双引号
}
$con = str_replace(array('<|YH|>'),array('\\"'),$con);//还原替换
return $con;
}
参考:http://bbs.csdn.net/topics/390496037
http://chenwei.me/p/59.html
作者:matrix
发布时间:2014-03-13
分类:零零星星
刚开始仅仅想获取一个他域的json数据,没想到牵扯到很多的问题。
每次都请求失败:
chrome面板的status为(canceled)
在Request Header这里显示CAUTION Provisional headers are shown
后来才知道是ajax的跨域问题导致:
也就是ajax同源策略(同源是指域名,协议,端口相同)。
跨域可以实现在自己的网站之间传递数据。但是如果你想用“跨域”盗取其它网站的数据,那还是放弃吧。除非目标网站有给你提供JSONP的接口,或者有某些可以利用的漏洞,要不然真没什么办法实现。
跨域问题的产生,最主要原因是COOKIE的安全问题。因为COOKIE是属于一个域的,如果允许跨域,客户端浏览器上储存的COOKIE就可以被它的所有者之外的程序访问到。举个例子吧,假如没有跨域问题,我现在就可以给百度发送个HTTP请求,获取你在百度上登录的用户名。或者获取SessionID,直接冒充你的帐号登录。为了避免这些问题,所以跨域访问的限制是非常有必要的。
利用jsonp跨域
要跨域必须要有回调函数的接口,这里用jsonp试试 阅读剩余部分 »