Golang中调用http.get或http.post请求时出现重定向循环问题
Golang中调用http.get或http.post请求时出现重定向循环问题
我对任何编程语言都是新手,但我已经开发了一个Go应用程序并部署在CloudFoundry中。在该应用程序中,我调用了一个方法,该方法又使用http.Get调用另一个应用程序的REST API。每当调用该方法时,它就会进入循环,并重复调用主方法10次。如何打破这个循环,使REST API调用只执行一次?只要我注释掉那个REST API调用,就不会出现循环。
这是我的代码:
response, err := http.Get("http://resturl.net")
defer response.Body.Close()
responseData, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Printf("The HTTP request failed with error %s\n", err)
}
fmt.Println("RESPONSE:", responseData)
如何解决这个问题……提前感谢。
更多关于Golang中调用http.get或http.post请求时出现重定向循环问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
顺便说一下,这是一个SlackBot应用程序。
更多关于Golang中调用http.get或http.post请求时出现重定向循环问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
sudheer: 每当调用该方法时,它都会循环并反复调用主方法10次
主方法是什么?请展示一下。
它将在POST处理程序中执行。如果我硬编码这些值…它不会循环,但当我调用这个REST API来获取值时。它会返回数值,但会再次提交并调用POST处理程序。
主方法:(Post Handler 正在循环)
func main() {
lg := log.New(os.Stdout, "slack-bot: ", log.Lshortfile|log.LstdFlags)
ctx := context.Background()
s, err := post.New()
if err != nil {
lg.Fatal(err)
}
s.Logger = lg
if err := s.Run(ctx); err != nil {
s.Logger.Fatal(err)
}
handler, err := s.NewHandler()
if err != nil {
s.Logger.Fatal(err)
}
port := os.Getenv("PORT")
if len(port) < 1 {
port = "8080"
}
fmt.Println("Listening on port", port)
http.ListenAndServe(":"+port, handler)
}
func (s *Slack) NewHandler() (http.Handler, error) {
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.NoCache)
r.Use(middleware.Heartbeat("/ping"))
cors := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
AllowCredentials: true,
MaxAge: 300, // 任何主流浏览器都不会忽略的最大值
})
r.Use(cors.Handler)
r.Get("/", indexHandler)
r.Post("/", postHandler)
r.Get("/debug/pprof/*", pprof.Index)
r.Get("/debug/vars", func(w http.ResponseWriter, r *http.Request) {
first := true
w.Header().Set("Content-Type", "application/json; charset=utf-8")
fmt.Fprintf(w, "{\n")
expvar.Do(func(kv expvar.KeyValue) {
if !first {
fmt.Fprintf(w, ",\n")
}
first = false
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
})
fmt.Fprintf(w, "\n}\n")
})
return r, nil
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("From INDEXHANDLER")
if r.URL.Path != "/" {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(fmt.Sprintf("incorrect path: %s", r.URL.Path)))
return
}
switch r.Method {
case "GET":
fmt.Println("FROM CASE GET")
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("%v", `¯\_(ツ)_/¯ GET`)))
return
case "POST":
fmt.Println("FROM CASE POST")
w.WriteHeader(http.StatusMovedPermanently)
w.Write([]byte("cannot post to this endpoint"))
return
default:
}
}
func postHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("In postHandler ***")
fmt.Println("r.Header", r.Header)
//fmt.Println("RESPONSE CODE FROM POSTHANDLER:", r.Response.StatusCode)
if r.URL.Path != "/" {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(fmt.Sprintf("incorrect path: %s", r.URL.Path)))
return
}
if r.Body == nil {
w.WriteHeader(http.StatusNotAcceptable)
w.Write([]byte("empty body"))
return
}
defer r.Body.Close()
err := r.ParseForm()
if err != nil {
w.WriteHeader(http.StatusGone)
w.Write([]byte("could not parse body"))
return
}
}
这是一个典型的HTTP重定向循环问题。当目标URL返回重定向状态码(如301、302)时,http.Get会自动跟随重定向,如果重定向链形成循环,就会导致无限重定向。
要解决这个问题,你需要创建一个自定义的HTTP客户端并禁用自动重定向,或者控制重定向行为。以下是几种解决方案:
方案1:完全禁用自动重定向
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// 创建自定义HTTP客户端,禁用重定向
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
// 返回此错误会停止重定向
return http.ErrUseLastResponse
},
}
// 使用自定义客户端发送请求
resp, err := client.Get("http://resturl.net")
if err != nil {
fmt.Printf("The HTTP request failed with error %s\n", err)
return
}
defer resp.Body.Close()
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Failed to read response body: %s\n", err)
return
}
fmt.Println("Status Code:", resp.StatusCode)
fmt.Println("RESPONSE:", string(responseData))
}
方案2:限制重定向次数
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// 创建自定义HTTP客户端,限制最大重定向次数
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
// 限制最多5次重定向
if len(via) >= 5 {
return fmt.Errorf("stopped after %d redirects", len(via))
}
return nil
},
}
resp, err := client.Get("http://resturl.net")
if err != nil {
fmt.Printf("The HTTP request failed with error %s\n", err)
return
}
defer resp.Body.Close()
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Failed to read response body: %s\n", err)
return
}
fmt.Println("RESPONSE:", string(responseData))
}
方案3:使用标准库的默认限制
Go的http.Client默认限制10次重定向,但你可以看到重定向链:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// 使用默认客户端,但添加自定义重定向处理来调试
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
fmt.Printf("Redirect %d: %s -> %s\n", len(via), via[len(via)-1].URL, req.URL)
// 默认行为(跟随重定向)
return nil
},
}
resp, err := client.Get("http://resturl.net")
if err != nil {
fmt.Printf("The HTTP request failed with error %s\n", err)
return
}
defer resp.Body.Close()
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Failed to read response body: %s\n", err)
return
}
fmt.Println("Final Status Code:", resp.StatusCode)
fmt.Println("RESPONSE:", string(responseData))
}
方案4:检查响应头以调试问题
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
resp, err := http.Get("http://resturl.net")
if err != nil {
fmt.Printf("The HTTP request failed with error %s\n", err)
return
}
defer resp.Body.Close()
// 打印响应头以查看是否有重定向
fmt.Println("Response Headers:")
for key, values := range resp.Header {
for _, value := range values {
fmt.Printf("%s: %s\n", key, value)
}
}
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Failed to read response body: %s\n", err)
return
}
fmt.Println("Status Code:", resp.StatusCode)
fmt.Println("RESPONSE:", string(responseData))
}
最可能的情况是,你的REST API返回了一个重定向到自身的URL,或者重定向链形成了循环。使用方案1完全禁用重定向是最直接的解决方案,但你可能需要根据实际需求选择合适的方法。


