duanjianl183188 2019-02-15 07:23
浏览 578
已采纳

如何重试HTTP POST请求

I have implemented the following code for retrying http post requests in Go.

In second retry attempt, I always get request body as null. I have tried defer req.body.close() but it is not working. Can anyone please help me this issue?

func httpRetry(req *http.Request, timeOut time.Duration, retryAttempts int, retryDelay time.Duration) (*http.Response, error) {

    attempts := 0

    for {
        attempts++
        fmt.Println("Attempt - ", attempts)
        statusCode := 0

        tr := &http.Transport{
            TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
        }
        var netClient = &http.Client{
            Timeout:   time.Second * timeOut,
            Transport: tr,
        }
        fmt.Println("ret 88888 ", req)
        response, err := netClient.Do(req)

        //defer req.Body.Close()

        fmt.Println(response, "  dd", err)

        if response != nil {
            fmt.Println(response.StatusCode)
            statusCode = response.StatusCode
        }

        if err != nil {
            fmt.Println(err)
            //return response, err
        }

        if err == nil && statusCode == http.StatusOK {
            return response, nil
        }

        if err == nil && response != nil {
            defer req.Body.Close()
        }

        retry := retryDecision(statusCode, attempts, retryAttempts)
        if !retry {
            return response, err
        }

        fmt.Println("Retry Attempt number", attempts)
        time.Sleep(retryDelay * time.Second)
        fmt.Println("After Delay")
    }
}

func retryDecision(responseStatusCode int, attempts int, retryAttempts int) bool {

    retry := false
    fmt.Println("Retry Decision 0 ", responseStatusCode, attempts, retryAttempts)
    errorCodeForRetry :=
        []int{http.StatusInternalServerError, http.StatusUnauthorized, http.StatusNotImplemented, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout}

    for _, code := range errorCodeForRetry {
        if code == responseStatusCode && attempts <= retryAttempts {
            retry = true
        }
    }

    fmt.Println("Retry Decision ", retry)

    return retry

}

Please find error details below

Attempt -  1
ret 88888  &{POST https://localhost:8080/logs/ HTTP/1.1 1 1 map[] {{"converstnId":"","boId":"","msgId":"","serviceName":"","headers":"","properties":"","message":"","body":"aa","exceptionMessage":"","logType":"","exceptionStackTrace":""}}

0x5ec890 170 [] false map[] map[] map[]
}

Attempt -  2
ret 88888  &{POST https://localhost:8080/logs/ HTTP/1.1 1 1 map[] {} 0x5ec890 170 [] false  map[] map[] <nil> map[]  

}

  • 写回答

1条回答 默认 最新

  • doudang4857 2019-02-15 09:30
    关注

    To be able to reuse a request whose body is non-nil, you first need to make sure that the body has been closed, not by you, but by the client's RoundTripper.

    the relevant part of the docs:

    RoundTrip must always close the body, including on errors, but depending on the implementation may do so in a separate goroutine even after RoundTrip returns. This means that callers wanting to reuse the body for subsequent requests must arrange to wait for the Close call before doing so.

    When reusing requests that don't have a body, like GET, you still need to be careful:

    If the request does not have a body, it can be reused as long as the caller does not mutate the Request until RoundTrip fails or the Response.Body is closed.

    Taken from here.

    So as long as you're sure that the RoundTripper closed the body, what you can do is to reset the body of the request at the top of each iteration. Something like this:

    func httpRetry(req *http.Request, timeOut time.Duration, retryAttempts int, retryDelay time.Duration) (*http.Response, error) {
    
        // ...
    
        data, err := ioutil.ReadAll(req.Body)
        if err != nil {
            return nil, err
        }
    
        // close the original body, we don't need it anymore
        if err := req.Body.Close(); err != nil {
            return err
        }
    
        for {
    
            req.Body = ioutil.NopCloser(bytes.NewReader(data)) // reset the body
    
            // ... your code ...
    
        }
    
        // ...
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 关于#python#的问题:自动化测试