go-zero读取请求体出现EOF错误的解决方法

 更新时间:2025年02月05日 08:32:54   作者:PandaMiner  
这篇文章主要为大家详细介绍了go-zero读取请求体出现EOF错误时如何解决,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

前言

最近自己在搭 go-zero 的脚手架,遇到一个问题,原先的一个 post 请求是执行成功,当我添加了一个过滤器之后执行该请求就会报错请求体读取 EOF 错误,我感到有点奇怪,为什么过滤器中的逻辑会影响到后续的请求呢?在此记录下这次的坑。

问题分析

先上结论,这是由于 go 中 http.Request.Body 请求体是一个流,它只能被读取一次,假如你在过滤器已经进行过流的读取,那么在后续的请求中就读取不到了。

示例的请求逻辑是这样,当请求到达后台时,先经过过滤器检查请求头中是否携带 token,否则则请求失败,成功则继续 post 请求逻辑,本次的 post 请求和过滤器只是做示例使用,逻辑很简单,过滤器中的逻辑就是去获取请求 header 中 token 字段,如果这个字段为空,则请求失败,代码示例如下:

func tokenFilter(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
       type Request struct {
          Token string `header:"token"`
       }
       var req Request
       err := httpx.Parse(r, &req)
       if err != nil || req.Token == "" {
          resp, _ := utils.ToJsonString(models.ErrorResponseWithCode(http.StatusUnauthorized, "token required"))
          routers.HttpError(w, http.StatusUnauthorized, resp)
          return
       }
       next(w, r)
    }
}

按照官方文档推荐,在过滤器我使用了 httpx.Parse(r, &req) 获取请求体数据,导致后续 post 请求逻辑读取请求体失败,也就是说,这个方法中会消耗掉请求体流的数据,查看源码可以发现,这个方法是会读取请求中的 path,form,header,body 数据,赋值到我们的 struct 中:

func Parse(r *http.Request, v any) error {
    kind := mapping.Deref(reflect.TypeOf(v)).Kind()
    if kind != reflect.Array && kind != reflect.Slice {
       if err := ParsePath(r, v); err != nil {
          return err
       }

       if err := ParseForm(r, v); err != nil {
          return err
       }

       if err := ParseHeaders(r, v); err != nil {
          return err
       }
    }

    if err := ParseJsonBody(r, v); err != nil {
       return err
    }

    if valid, ok := v.(validation.Validator); ok {
       return valid.Validate()
    } else if val := validator.Load(); val != nil {
       return val.(Validator).Validate(r, v)
    }

    return nil
}

继续往下查看源码可以发现,其中的 ParseForm 方法和 ParseJsonBody 方法就会消耗掉请求体流的数据,ParsePath 方法 ParseHeaders 方法则不会,而在这个过滤器中,我们只需要获取 header 的数据,body 的数据需要由后续逻辑获取,所以在这里需要修改过滤只获取 header 数据的方法,如果需要的是 path 数据也是同样的道理,修改后的过滤器:

func tokenFilter(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
       type Request struct {
          Token string `header:"token"`
       }
       var req Request
       err := httpx.ParseHeaders(r, &req)
       if err != nil || req.Token == "" {
          resp, _ := utils.ToJsonString(models.ErrorResponseWithCode(http.StatusUnauthorized, "token required"))
          routers.HttpError(w, http.StatusUnauthorized, resp)
          return
       }
       next(w, r)
    }
}

修改后后续节点即可正常获取请求体数据。

完整示例代码请参考:igolang

到此这篇关于go-zero读取请求体出现EOF错误的解决方法的文章就介绍到这了,更多相关解决go-zero读取请求体出现EOF错误内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决goland中编辑tpl文件不高亮没智能补全的问题

    解决goland中编辑tpl文件不高亮没智能补全的问题

    这篇文章主要介绍了解决goland中编辑tpl文件不高亮没智能补全的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • golang的HTTP基本认证机制实例详解

    golang的HTTP基本认证机制实例详解

    这篇文章主要介绍了golang的HTTP基本认证机制,结合实例形式较为详细的分析了HTTP请求响应的过程及认证机制实现技巧,需要的朋友可以参考下
    2016-07-07
  • 深入理解Golang channel的应用

    深入理解Golang channel的应用

    channel是用于 goroutine 之间的同步、通信的数据结构。它为程序员提供了更高一层次的抽象,封装了更多的功能,这样并发编程变得更加容易和安全。本文通过示例为大家详细介绍了channel的应用,需要的可以参考一下
    2022-10-10
  • Golang 关于Gin框架请求参数的获取方法

    Golang 关于Gin框架请求参数的获取方法

    Gin是Go语言的Web框架,提供路由和中间件支持,本文介绍如何使用Gin获取HTTP请求参数,包括URLPath参数、URLQuery参数、HTTPBody参数和Header参数,详解直接获取和绑定到结构体两种方法,帮助开发者高效处理Web请求
    2024-10-10
  • Go项目实现优雅关机与平滑重启功能

    Go项目实现优雅关机与平滑重启功能

    无论是优雅关机还是优雅重启归根结底都是通过监听特定系统信号,然后执行一定的逻辑处理保障当前系统正在处理的请求被正常处理后再关闭当前进程,这篇文章主要介绍了Go实现优雅关机与平滑重启 ,需要的朋友可以参考下
    2022-10-10
  • Golang调用FFmpeg转换视频流的实现

    Golang调用FFmpeg转换视频流的实现

    本文主要介绍了Golang调用FFmpeg转换视频流,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 在Go语言单元测试中解决HTTP网络依赖问题

    在Go语言单元测试中解决HTTP网络依赖问题

    在 Go 语言中,我们需要找到一种可靠的方法来测试 HTTP 请求和响应,本文将探讨在 Go 中进行 HTTP 应用测试时,如何解决应用程序的依赖问题,以确保我们能够编写出可靠的测试用例,需要的朋友可以参考下
    2023-07-07
  • Golang的第一个程序-Hello World

    Golang的第一个程序-Hello World

    这篇文章主要介绍了第一个Go程序-Hello World,在编写第一个go程序之前,我们要将系统的环境变量配好,下面来看具体的编一过程吧,需要的小伙伴可以参考一下
    2022-01-01
  • Go 通过结构struct实现接口interface的问题

    Go 通过结构struct实现接口interface的问题

    这篇文章主要介绍了Go 通过结构struct实现接口interface的问题,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10
  • 详解Golang中Channel的原理和使用技巧

    详解Golang中Channel的原理和使用技巧

    Channel管道提供了一种机制,它在两个并发执行的协程之间进行同步,并通过传递与该管道元素类型相符的值来进行通信。本文主要介绍了Channel的原理和使用技巧,需要的可以参考一下
    2022-11-11

最新评论