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

6 回复

顺便说一下,这是一个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完全禁用重定向是最直接的解决方案,但你可能需要根据实际需求选择合适的方法。

回到顶部