Gin框架Context.Redirect单元测试:POST请求返回200而非302问题
Gin单元测试中POST请求Redirect返回200而非302的问题解决
我需要让服务器将特定端点重定向到另一服务器,该端点支持GET和POST请求,两种场景都要返回302状态码。用curl测试时,两种请求都返回302,且curl -L能正常跟随重定向;但用httptest.NewRecorder写单元测试时,GET请求正常返回302,POST请求却返回200,不是预期的http.StatusFound。
测试运行输出
$ go run foo.go POST code 200 GET code 302
完整测试代码
package main import ( "net/http" "net/http/httptest" "github.com/gin-gonic/gin" ) func main() { gin.SetMode(gin.ReleaseMode) { w := httptest.NewRecorder() context, _ := gin.CreateTestContext(w) context.Request = httptest.NewRequest("POST", "http://localhost:23632/foobar", nil) context.Redirect(http.StatusFound, "http://foobar.com") print("POST code ",w.Code,"\n") } { w := httptest.NewRecorder() context, _ := gin.CreateTestContext(w) context.Request = httptest.NewRequest("GET", "http://localhost:23632/foobar", nil) context.Redirect(http.StatusFound, "http://foobar.com") print("GET code ",w.Code,"\n") } }
实际curl POST测试结果
curl -v -XPOST localhost:23632/foobar * About to connect() to localhost port 23632 (#0) * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 23632 (#0) > POST /foobar HTTP/1.1 > User-Agent: curl/7.29.0 > Host: localhost:23632 > Accept: */* > < HTTP/1.1 302 Found < Location: http://foobar.com < Vary: Origin < Date: Tue, 23 May 2023 22:38:42 GMT < Content-Length: 0 < * Connection #0 to host localhost left intact
问题原因
原测试代码直接调用context.Redirect,未经过Gin路由的完整处理流程。Gin针对POST请求调用Redirect时,默认会生成一个自动提交的HTML表单(返回200状态码),这是框架为兼容浏览器POST重定向场景的默认行为;但实际通过路由处理请求时,Gin会根据客户端类型返回正确的302状态码(curl这类非浏览器客户端会直接收到302)。
解决方法
方法1:模拟完整路由请求流程
按照实际应用的路由注册方式编写测试,让请求经过Gin的完整处理流程:
package main import ( "net/http" "net/http/httptest" "github.com/gin-gonic/gin" ) func main() { gin.SetMode(gin.ReleaseMode) // 创建路由并注册处理函数 r := gin.Default() r.Any("/foobar", func(c *gin.Context) { c.Redirect(http.StatusFound, "http://foobar.com") }) // 测试POST请求 { w := httptest.NewRecorder() req := httptest.NewRequest("POST", "http://localhost:23632/foobar", nil) r.ServeHTTP(w, req) print("POST code ", w.Code, "\n") // 此时返回302 } // 测试GET请求 { w := httptest.NewRecorder() req := httptest.NewRequest("GET", "http://localhost:23632/foobar", nil) r.ServeHTTP(w, req) print("GET code ", w.Code, "\n") } }
方法2:手动设置状态码和响应头
如果需要直接操作Context,可以绕过Gin的默认重定向处理,手动设置状态码和Location头:
// 替换原context.Redirect调用 context.Status(http.StatusFound) context.Header("Location", "http://foobar.com")
内容的提问来源于stack exchange,提问作者Mark Lakata
相关产品推荐
相关产品推荐

