我已经尝试解决一个奇怪的问题了一段时间了。在浏览了许多棱角分明的代码之后,当我通过Charles将请求记录到服务器时,我注意到了一些奇怪的东西。
当我发布到url时/myurl,请求实际上不会到达我的服务器。相反,它收到301响应,然后GET请求命中了我的服务器。
/myurl
这令人难以置信。还有其他人遇到这个问题吗?如果您有兴趣,我已经上传了我的Charles日志的屏幕截图。
作为参考,这是我的服务器的外观:
type FormStruct struct { Test string } func PHandler(w http.ResponseWriter, r *http.Request) { var t FormStruct req, _ := httputil.DumpRequest(r, true) log.Println(string(req)) log.Println(r.Method) // GET log.Println(r.Body) decoder := json.NewDecoder(r.Body) err := decoder.Decode(&t) log.Println("Decoding complete") if err != nil { log.Println("Error") panic(err.Error()+"\n\n") } log.Println(t.Test) w.Write([]byte("Upload complete, no errors")) } func main() { http.HandleFunc("/myurl/", PHandler) fmt.Println("Go Server listening on port 8001") http.ListenAndServe(":8001", nil) }
解释很简单:因为"/myurl/"注册时使用了路径PHandler(请注意末尾有斜杠/!),但您却将浏览器定向到了/myurl(请注意没有后缀正斜杠)。默认情况下,http程序包实现将执行(发送回)重定向请求,因此,如果浏览器遵循该重定向请求(它将执行),则新URL将匹配注册的路径。
"/myurl/"
PHandler
/
http
记录在类型http.ServeMux:
http.ServeMux
如果已经注册了一个子树,并且接收到一个命名该子树根的请求而没有其后斜杠,则ServeMux将该请求重定向到该子树根(添加后斜杠)。 可以用单独的路径注册来覆盖此行为,而不必使用斜杠。例如,注册“ / images /”会使ServeMux将对“ / images”的请求重定向到“ / images /”,除非已单独注册了“ / images”。
如果您将浏览器直接/myurl/定向到,则不会遇到重定向。
/myurl/
或者,如果您不需要处理有根的子树,而只需要处理一个路径(例如/myurl),则仅将处理程序注册到该路径:
http.HandleFunc("/myurl", PHandler)
然后,当然将您的浏览器/myurl定向到,也不会遇到任何重定向。
…或者如文档所示:如果确实需要,请注册到处理程序的两个路径:
http.HandleFunc("/myurl", PHandler) http.HandleFunc("/myurl/", PHandler)
现在,无论您调用(/myurl或/myurl/)哪个路径,两者都将导致调用处理程序而不会发生任何重定向。
笔记:
在您将重定向发送回浏览器的情况下,浏览器将不会重复POST请求(而只会重复“简单” GET请求)。
一般而言,浏览器不会将POST数据发送到重定向URL,因为该浏览器没有资格决定您是否愿意将要发送的数据发送到新URL(打算将其发送到原始URL)(请考虑密码,信用卡号和其他敏感数据)。但不要试图绕过它,只需使用处理程序的注册路径(POST到)或上述任何其他技巧即可。