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错误内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go带缓冲chan实现消息队列功能

    go带缓冲chan实现消息队列功能

    本文主要介绍了go带缓冲chan实现消息队列功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • Golang绘制数列趋势图的操作步骤

    Golang绘制数列趋势图的操作步骤

    数列趋势图是用来表示数列中各项之间的变化趋势的图形,它可以帮助我们观察和分析数列的规律和特点,一般来说,数列趋势图可以分为两种类型:折线图和散点图,本文给大家介绍了Golang绘制数列趋势图的操作步骤,文中有详细的代码示例,需要的朋友可以参考下
    2024-04-04
  • Go语言中init函数与匿名函数使用浅析

    Go语言中init函数与匿名函数使用浅析

    这篇文章主要介绍了Go语言中init函数与匿名函数使用浅析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-01-01
  • 从浅入深带你掌握Golang数据结构map

    从浅入深带你掌握Golang数据结构map

    在 Go 语言中,map 是一种非常常见的数据类型,它可以用于快速地检索数据。本篇文章将介绍 Go 语言中的 map,包括 map 的定义、初始化、操作和优化,需要的可以参考一下
    2023-04-04
  • Go 实现热重启的详细介绍

    Go 实现热重启的详细介绍

    这篇文章主要介绍了Go 实现热重启的详细介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Go语言中协程泄漏的问题排查与实战指南

    Go语言中协程泄漏的问题排查与实战指南

    这篇文章主要为大家详细介绍了Go语言中协程泄漏的4 种常见泄漏模式的可运行代码以及修复方案,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下
    2026-04-04
  • 详解Golang中单元测试的使用

    详解Golang中单元测试的使用

    单元测试是检测你写的一个函数是否具备安全性的一次检测,这篇文章主要为大家详细介绍了Golang中单元测试的具体使用,希望对大家有所帮助
    2023-07-07
  • go mod 使用私有gitlab群组的解决方案

    go mod 使用私有gitlab群组的解决方案

    这篇文章主要介绍了go mod 使用私有gitlab群组的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • GO语言运行环境下载、安装、配置图文教程

    GO语言运行环境下载、安装、配置图文教程

    这篇文章主要介绍了GO语言运行环境下载、安装、配置图文教程,需要的朋友可以参考下
    2017-02-02
  • Go中gin框架的*gin.Context参数常见实用方法

    Go中gin框架的*gin.Context参数常见实用方法

    *gin.Context是处理HTTP请求的核心,ctx代表"context"(上下文),它包含了处理请求所需的所有信息和方法,例如请求数据、响应构建器、路由参数等,这篇文章主要介绍了Go中gin框架的*gin.Context参数常见实用方法,需要的朋友可以参考下
    2024-07-07

最新评论