最近开发了一个基于Gin框架的软件,对外提供HTTP接口服务。在开发阶段使用Postman进行接口自测时功能一切正常,但部署到生产环境后,与调用方联调时发现大部分接口工作正常,唯独一个POST接口总是返回307状态码。通过抓包分析和消息对比均未发现异常,用Postman测试相同请求也能正常响应,唯独调用方的请求持续返回307。

代码示例如下:

func main() {

    router := gin.Default()

    err := router.Run(":8080")

    router.GET("/user", func(c *gin.Context) {
        c.String(http.StatusOK, "张三")
    })

    router.POST("/user/", func(c *gin.Context) {

        body, errRead := io.ReadAll(c.Request.Body)

        if errRead != nil {
            c.String(http.StatusInternalServerError, "get body error")
            return
        }

        fmt.Println(string(body))

        c.String(http.StatusOK, "")
    })

    if err != nil {
        fmt.Errorf("start http failed\n%v", err.Error())
        return
    }
}

经过一段时间的排查,问题终于得到解决。现将具体原因和解决方法分享如下:

原因分析

 

通过查看gin源码gin.go文件中Engine结构体由有一个RedirectTrailingSlash字段,源码如下:

RedirectTrailingSlash字段注释翻译如下:

RedirectTrailingSlash 启用自动重定向:当前路由不匹配但存在带(或不带)尾部斜杠的路径处理程序时生效。  
例如:若请求路径为 /foo/ 但仅存在 /foo 的路由,  
客户端将被重定向至 /foo——GET 请求返回 HTTP 状态码 301,其他请求方法返回 307

RedirectTrailingSlash字段的注释说明:当Gin框架定义的URL以斜杠结尾(如/user/)且请求方法为GET时,访问/user/路径会返回301响应;对于POST、PUT、DELETE等请求方法,访问该URL则会返回307响应。

检查代码中的URL定义后发现,问题出在URL末尾多了一个斜杠。删除该斜杠后,接口访问恢复正常。

解决方法

方法一:统一路由定义

 

按照接口文档要求,统一路由路径的格式规范,确保注册路径(无论是否带斜杠)与实际请求路径保持一致,

如接口中定义URL为/user/,服务提供者和访问者都按照/user/进行处理。

方法二:CORS 配置

使用第三方库github.com/gin-contrib/cors实现解决,代码示例如下:

router := gin.Default()

router.Use(cors.Default())

gin-contrib/cors中间件能够有效处理前后端分离架构中的跨域请求问题。

方法三:关闭RedirectTrailingSlash

推荐关闭RedirectTrailingSlash配置,这样当访问/user而实际URL为/user/时,系统会直接返回404错误。这种方式能快速区分是URL路径错误还是请求方法不匹配的问题。

代码示例如下:

router := gin.Default()
router.RedirectTrailingSlash = false

为什么postman访问没问题,调用者响应307呢?

 

部分浏览器和客户端访问时会触发 307 重定向,而 Postman 能同时兼容这两种 URL 格式且不会报错。这源于 Gin 框架的路由匹配机制对 URL 规范化的要求较为宽松,而某些客户端则会严格执行 HTTP 协议规范。

 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐