在使用Go语言编写Web应用程序时,我们经常会用到gin框架来处理HTTP请求和响应。在进行单元测试时,我们需要对代码进行覆盖测试,以保证代码的质量和稳定性。然而,针对gin的Context.Redirect方法的单元测试在处理GET请求时非常适用,但在处理POST请求时却不太适用。在本文中,php小编苹果将会详细解释为什么这个问题会出现,并提供一些解决方案来进行POST请求的单元测试。
我希望我的服务器将特定端点重定向到另一台服务器。该端点可以是 get
ted 或 post
ed。在这两种情况下,http 响应代码都应为 302。如果我在此代码上使用 curl
,它确实在两种情况下都显示响应代码 302,并且 curl -l
正确遵循重定向。哇哦。
但是
我的单元测试使用httptest.newrecorder()
来捕获信息,但它仅适用于get
,不适用于post
。因此,当我知道实际的重定向正在工作时,我需要弄清楚如何让单元测试工作。失败测试显示http响应代码是200而不是302(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
之后显式调用 context.writer.writeheadernow
。
这是使用从 gin.createtestcontext
返回的 gin 上下文的一个极端情况。
对于 get 请求,gin 最终会调用 http.redirect
,它将向响应写入一个简短的 html 正文(类似于 64ac7c208db62edaa9346a44958f6a3efound5db79b134e9f6b82c0b36e0489ee08ed
),从而导致要写入响应的状态代码。
对于 post 请求,http.redirect
不会写入短 html 正文,并且状态代码没有机会写入响应。
参见http 的实现.重定向。根据源码,如果之前设置了content-type
header,那么get请求也会出现同样的问题:
{ w := httptest.newrecorder() context, _ := gin.createtestcontext(w) context.request = httptest.newrequest("get", "http://localhost:23632/foobar", nil) + context.header("content-type", "text/html") context.redirect(http.statusfound, "http://foobar.com") print("get code ", w.code, "\n") }
解决方法是显式调用 context.writer.writeheadernow
:
{ w := httptest.NewRecorder() context, _ := gin.CreateTestContext(w) context.Request = httptest.NewRequest("POST", "http://localhost:23632/foobar", nil) context.Redirect(http.StatusFound, "http://foobar.com") + context.Writer.WriteHeaderNow() print("POST code ", w.Code, "\n") }
gin 本身使用相同的解决方法。请参阅 testcontextrenderredirectwithrelativepath。
真正的服务器应用程序不会遇到同样的问题,因为 (*engine).handlehttprequest
将为我们调用 writeheadernow
(请参阅 源代码)。这就是为什么我称其为“极端情况”而不是“错误”。
以上是gin 的 Context.Redirect 的单元测试适用于 GET 响应代码,但不适用于 POST 响应代码 (golang)的详细内容。更多信息请关注PHP中文网其他相关文章!