我的编程空间,编程开发者的网络收藏夹
学习永远不晚

使用gin解析json格式数据时出错如何解决

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

使用gin解析json格式数据时出错如何解决

使用gin解析json格式数据时出错如何解决?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

写的接口给测试测试,现在还没有页面,直接测试接口。使用

c.BindJSON(&req)

总是报错,大致错误信息如下:

err="invalid character '-' in numeric literal"

这是由于我的接口要求将参数按照json格式传递到后台,结果测试同事使用了form-data格式,所以才会有上面这个错误。

=============补充2018-11-09 18:20:00=============

刚刚又出现了这个EOF的问题,前端确定已经按照json格式传参,但是还是有这个问题。

通过wireshark抓包发现,前端给的Content-Length为0,说明没有将参数传入后台。

后来前端核查代码发现,确实是没有将参数传入,只是定义了

补充:gin json 获取_Gin框架系列 自定义错误处理

概述

很多读者在后台向我要 Gin 框架实战系列的 Demo 源码,在这里再说明一下,源码我都更新到 GitHub 上,地址:https://github.com/xinliangnote/Go

开始今天的文章,为什么要自定义错误处理?默认的错误处理方式是什么?

那好,咱们就先说下默认的错误处理。

默认的错误处理是 errors.New("错误信息"),这个信息通过 error 类型的返回值进行返回。

举个简单的例子:

func hello(name string) (str string, err error) {if name == "" {err = errors.New("name 不能为空")return}str = fmt.Sprintf("hello: %s", name)return}

当调用这个方法时:

var name = ""str, err := hello(name)if err != nil {fmt.Println(err.Error())return}

这就是默认的错误处理,下面还会用这个例子进行说。

这个默认的错误处理,只是得到了一个错误信息的字符串。

然而...

我还想得到发生错误时的 时间、 文件名、 方法名、 行号 等信息。

我还想得到错误时进行告警,比如 短信告警、 邮件告警、 微信告警 等。

我还想调用的时候,不那么复杂,就和默认错误处理类似,比如:

alarm.WeChat("错误信息")return

这样,我们就得到了我们想要的信息( 时间、 文件名、 方法名、 行号),并通过 微信 的方式进行告警通知我们。

同理, alarm.Email("错误信息")、 alarm.Sms("错误信息") 我们得到的信息是一样的,只是告警方式不同而已。

还要保证,我们业务逻辑中,获取错误的时候,只获取错误信息即可。

上面这些想出来的,就是今天要实现的,自定义错误处理,我们就实现之前,先说下 Go 的错误处理。

错误处理

package mainimport ("errors""fmt")func hello(name string) (str string, err error) {if name == "" {err = errors.New("name 不能为空")return}str = fmt.Sprintf("hello: %s", name)return}func main() {var name = ""fmt.Println("param:", name)str, err := hello(name)if err != nil {fmt.Println(err.Error())return}fmt.Println(str)}

输出:

param: Tom

hello: Tom

当 name = "" 时,输出:

param:

name 不能为空

建议每个函数都要有错误处理,error 应该为最后一个返回值。

咱们一起看下官方 errors.go

// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Package errors implements functions to manipulate errors.package errors// New returns an error that formats as the given text.func New(text string) error {return &errorString{text}}// errorString is a trivial implementation of error.type errorString struct {s string}func (e *errorString) Error() string {return e.s}

上面的代码,并不复杂,参照上面的,咱们进行写一个自定义错误处理。

自定义错误处理

咱们定义一个 alarm.go,用于处理告警。

废话不多说,直接看代码。

package alarmimport ("encoding/json""fmt""ginDemo/common/function""path/filepath""runtime""strings")type errorString struct {s string}type errorInfo struct {Time string `json:"time"`Alarm string `json:"alarm"`Message string `json:"message"`Filename string `json:"filename"`Line int `json:"line"`Funcname string `json:"funcname"`}func (e *errorString) Error() string {return e.s}func New (text string) error {alarm("INFO", text)return &errorString{text}}// 发邮件func Email (text string) error {alarm("EMAIL", text)return &errorString{text}}// 发短信func Sms (text string) error {alarm("SMS", text)return &errorString{text}}// 发微信func WeChat (text string) error {alarm("WX", text)return &errorString{text}}// 告警方法func alarm(level string, str string) {// 当前时间currentTime := function.GetTimeStr()// 定义 文件名、行号、方法名fileName, line, functionName := "?", 0 , "?"pc, fileName, line, ok := runtime.Caller(2)if ok {functionName = runtime.FuncForPC(pc).Name()functionName = filepath.Ext(functionName)functionName = strings.TrimPrefix(functionName, ".")}var msg = errorInfo {Time : currentTime,Alarm : level,Message : str,Filename : fileName,Line : line,Funcname : functionName,}jsons, errs := json.Marshal(msg)if errs != nil {fmt.Println("json marshal error:", errs)}errorJsonInfo := string(jsons)fmt.Println(errorJsonInfo)if level == "EMAIL" {// 执行发邮件} else if level == "SMS" {// 执行发短信} else if level == "WX" {// 执行发微信} else if level == "INFO" {// 执行记日志}}

看下如何调用:

package v1import ("fmt""ginDemo/common/alarm""ginDemo/entity""github.com/gin-gonic/gin""net/http")func AddProduct(c *gin.Context) {// 获取 Get 参数name := c.Query("name")var res = entity.Result{}str, err := hello(name)if err != nil {res.SetCode(entity.CODE_ERROR)res.SetMessage(err.Error())c.JSON(http.StatusOK, res)c.Abort()return}res.SetCode(entity.CODE_SUCCESS)res.SetMessage(str)c.JSON(http.StatusOK, res)}func hello(name string) (str string, err error) {if name == "" {err = alarm.WeChat("name 不能为空")return}str = fmt.Sprintf("hello: %s", name)return}

访问:http://localhost:8080/v1/product/add?name=a

{"code": 1,"msg": "hello: a","data": null}

未抛出错误,不会输出信息。

访问:http://localhost:8080/v1/product/add

{"code": -1,"msg": "name 不能为空","data": null}

抛出了错误,输出信息如下:

{"time":"2019-07-23 22:19:17","alarm":"WX","message":"name 不能为空","filename":"绝对路径/ginDemo/router/v1/product.go","line":33,"funcname":"hello"}

可能这会有同学说:“用上一篇分享的数据绑定和验证,将传入的参数进行 binding:"required" 也可以实现呀”。

我只能说:“同学呀,你不理解我的良苦用心,这只是个例子,大家可以在一些复杂的业务逻辑判断场景中使用自定义错误处理”。

到这里,报错时我们收到了 时间、 错误信息、 文件名、 行号、 方法名 了。

调用起来,也比较简单。

虽然标记了告警方式,还是没有进行告警通知呀。

我想说,在这里存储数据到队列中,再执行异步任务具体去消耗,这块就不实现了,大家可以去完善。

读取 文件名、 方法名、 行号 使用的是 runtime.Caller()。

我们还知道,Go 有 panic 和 recover,它们是干什么的呢,接下来咱们就说说。

panic 和 recover

当程序不能继续运行的时候,才应该使用 panic 抛出错误。

当程序发生 panic 后,在 defer(延迟函数) 内部可以调用 recover 进行控制,不过有个前提条件,只有在相同的 Go 协程中才可以。

panic 分两个,一种是有意抛出的,一种是无意的写程序马虎造成的,咱们一个个说。

有意抛出的 panic:

package mainimport ("fmt")func main() {fmt.Println("-- 1 --")defer func() {if r := recover(); r != nil {fmt.Printf("panic: %s\n", r)}fmt.Println("-- 2 --")}()panic("i am panic")}

输出:

-- 1 --

panic: i am panic

-- 2 --

无意抛出的 panic:

package mainimport ("fmt")func main() {fmt.Println("-- 1 --")defer func() {if r := recover(); r != nil {fmt.Printf("panic: %s\n", r)}fmt.Println("-- 2 --")}()var slice = [] int {1, 2, 3, 4, 5}slice[6] = 6}

输出:

-- 1 --

panic: runtime error: index out of range

-- 2 --

上面的两个我们都通过 recover 捕获到了,那我们如何在 Gin 框架中使用呢?如果收到 panic 时,也想进行告警怎么实现呢?

既然想实现告警,先在 ararm.go 中定义一个 Panic() 方法,当项目发生 panic 异常时,调用这个方法,这样就实现告警了。

// Panic 异常func Panic (text string) error {alarm("PANIC", text)return &errorString{text}}

那我们怎么捕获到呢?

使用中间件进行捕获,写一个 recover 中间件。

package recoverimport ("fmt""ginDemo/common/alarm""github.com/gin-gonic/gin")func Recover() gin.HandlerFunc {return func(c *gin.Context) {defer func() {if r := recover(); r != nil {alarm.Panic(fmt.Sprintf("%s", r))}}()c.Next()}}

路由调用中间件:

r.Use(logger.LoggerToFile(), recover.Recover())//Use 可以传递多个中间件。

验证下吧,咱们先抛出两个异常,看看能否捕获到?

还是修改 product.go 这个文件吧。

有意抛出 panic:

package v1import ("fmt""ginDemo/entity""github.com/gin-gonic/gin""net/http")func AddProduct(c *gin.Context) {// 获取 Get 参数name := c.Query("name")var res = entity.Result{}str, err := hello(name)if err != nil {res.SetCode(entity.CODE_ERROR)res.SetMessage(err.Error())c.JSON(http.StatusOK, res)c.Abort()return}res.SetCode(entity.CODE_SUCCESS)res.SetMessage(str)c.JSON(http.StatusOK, res)}func hello(name string) (str string, err error) {if name == "" {// 有意抛出 panicpanic("i am panic")return}str = fmt.Sprintf("hello: %s", name)return}

访问:http://localhost:8080/v1/product/add

界面是空白的。

抛出了异常,输出信息如下:

{"time":"2019-07-23 22:42:37","alarm":"PANIC","message":"i am panic","filename":"绝对路径/ginDemo/middleware/recover/recover.go","line":13,"funcname":"1"}

很显然,定位的文件名、方法名、行号不是我们想要的。

需要调整 runtime.Caller(2),这个代码在 alarm.go的alarm 方法中。

将 2 调整成 4 ,看下输出信息:

{"time":"2019-07-23 22:45:24","alarm":"PANIC","message":"i am panic","filename":"绝对路径/ginDemo/router/v1/product.go","line":33,"funcname":"hello"}

这就对了。

无意抛出 panic:

// 上面代码不变func hello(name string) (str string, err error) {if name == "" {// 无意抛出 panicvar slice = [] int {1, 2, 3, 4, 5}slice[6] = 6return}str = fmt.Sprintf("hello: %s", name)return}

访问:http://localhost:8080/v1/product/add

界面是空白的。

抛出了异常,输出信息如下:

{"time":"2019-07-23 22:50:06","alarm":"PANIC","message":"runtime error: index out of range","filename":"绝对路径/runtime/panic.go","line":44,"funcname":"panicindex"}

很显然,定位的文件名、方法名、行号也不是我们想要的。

将 4 调整成 5 ,看下输出信息:

{"time":"2019-07-23 22:55:27","alarm":"PANIC","message":"runtime error: index out of range","filename":"绝对路径/ginDemo/router/v1/product.go","line":34,"funcname":"hello"}

这就对了。

奇怪了,这是为什么?

在这里,有必要说下 runtime.Caller(skip) 了。

skip 指的调用的深度。

为 0 时,打印当前调用文件及行数。

为 1 时,打印上级调用的文件及行数。

依次类推...

在这块,调用的时候需要注意下,我现在还没有好的解决方案。

我是将 skip(调用深度),当一个参数传递进去。

比如:

// 发微信func WeChat (text string) error {alarm("WX", text, 2)return &errorString{text}}// Panic 异常func Panic (text string) error {alarm("PANIC", text, 5)return &errorString{text}}

看完上述内容,你们掌握使用gin解析json格式数据时出错如何解决的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网行业资讯频道,感谢各位的阅读!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

使用gin解析json格式数据时出错如何解决

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

使用gin解析json格式数据时出错如何解决

使用gin解析json格式数据时出错如何解决?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。写的接口给测试测试,现在还没有页面,直接测试接口。使用c.BindJSON(&req)
2023-06-14

Ajax中如何解析json格式数据

在Ajax中,可以使用`JSON.parse()`方法来解析JSON格式的数据。示例代码如下:```javascriptvar xmlhttp = new XMLHttpRequest();xmlhttp.onreadystatechang
2023-09-04

在golang中使用Unmarshal将json赋给struct时出错如何解决

在golang中使用Unmarshal将json赋给struct时出错如何解决?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。将json:{ "name": "L
2023-06-14

plsql导出csv格式数据异常如何解决

如果在PL/SQL中导出CSV格式的数据时遇到异常,可能有以下几种解决方法:1.检查查询语句:确保查询语句正确无误,包括表名、列名、条件等都应该正确。2.检查导出路径:确保导出路径的文件夹存在,并且有足够的权限进行写入操作。3.检查文件编码
2023-09-28

使用IDEA连接mysql数据库时出现报错如何解决

使用IDEA连接mysql数据库时出现报错如何解决?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。IDEA连接mysql数据库出现Server returns i
2023-06-15

使用studio时出现java.lang.UnsatisfiedLinkError报错如何解决

这篇文章将为大家详细讲解有关使用studio时出现java.lang.UnsatisfiedLinkError报错如何解决,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。studio中碰到的j
2023-05-31

使用Unity3D时出现DllNotFoundException错误如何解决

这篇文章给大家介绍使用Unity3D时出现DllNotFoundException错误如何解决,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。起因unity程序build到pc上,拿到其他人的机器上结果有些功能不正常,看
2023-06-14

C#中如何使用XML和JSON数据格式进行数据存储和传输及解决方法

C#中如何使用XML和JSON数据格式进行数据存储和传输及解决方法XML和JSON是目前广泛应用于数据交换和存储的两种标准格式。在C#中,我们可以使用内置的库和工具来处理和操作XML和JSON数据。本文将详细介绍如何在C#中使用XML和JS
2023-10-22

wordpress建立数据库连接时出错如何解决

在WordPress建立数据库连接时出现问题可能有多种原因。以下是一些常见的解决方法:1. 检查数据库凭据:确保在wp-config.php文件中输入了正确的数据库名称、用户名和密码。可以通过登录到数据库管理界面来验证这些凭据。2. 检查数
2023-10-10

Vue格式化数据后切换页面出现NaN如何解决

这篇文章主要介绍“Vue格式化数据后切换页面出现NaN如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue格式化数据后切换页面出现NaN如何解决”文章能帮助大家解决问题。格式化数据后切换页面
2023-06-30

使用PyTorch训练LSTM时出现loss.backward()报错如何解决

使用PyTorch训练LSTM时出现loss.backward()报错如何解决?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。正确做法:LSRM / RNN模块初始化时定义好hi
2023-06-15

在Android 中使用Caused时出现java.lang.ClassNotFoundException报错如何解决

本篇文章为大家展示了在Android 中使用Caused时出现java.lang.ClassNotFoundException报错如何解决,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。出现问题:08
2023-05-31

使用Spring Boot时出现“be auto-configured, check ....”报错如何解决

今天就跟大家聊聊有关使用Spring Boot时出现“be auto-configured, check ....”报错如何解决,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Spri
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录