Golang调用REST API时遇到的HTTP POST问题

Golang调用REST API时遇到的HTTP POST问题 我有一个非常简单的GO程序,它调用一个REST API并将此消息发布到Slack频道。

每当REST API需要较长时间响应时,Go应用程序会再次发布REST API。

是否有需要更新的设置,以便让GO应用程序等待而不是再次触发REST API?

以下是我调用REST API的方式:

jsonValue, _ := json.Marshal(jvalues)
response, err := http.Post("http://posturl", "application/json", bytes.NewBuffer(jsonValue))

Go版本:go1.13.6 darwin/amd64

以前有人遇到过这个问题吗?


更多关于Golang调用REST API时遇到的HTTP POST问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang调用REST API时遇到的HTTP POST问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中调用HTTP POST时遇到重复请求的问题,通常是由于没有正确处理请求超时和重试机制导致的。当HTTP请求耗时较长且没有设置适当的超时时间时,可能会触发默认的重试行为或客户端超时后重新发起请求。

以下是解决方案和示例代码:

1. 设置自定义HTTP客户端并配置超时

package main

import (
    "bytes"
    "encoding/json"
    "net/http"
    "time"
)

func main() {
    // 创建自定义HTTP客户端,设置超时时间
    client := &http.Client{
        Timeout: 30 * time.Second, // 设置30秒超时
    }

    jvalues := map[string]interface{}{
        "text": "Hello, Slack!",
    }
    
    jsonValue, _ := json.Marshal(jvalues)
    
    // 创建请求
    req, err := http.NewRequest("POST", "http://posturl", bytes.NewBuffer(jsonValue))
    if err != nil {
        // 处理错误
        return
    }
    
    req.Header.Set("Content-Type", "application/json")
    
    // 发送请求
    response, err := client.Do(req)
    if err != nil {
        // 处理错误
        return
    }
    defer response.Body.Close()
    
    // 处理响应
}

2. 禁用HTTP/2的自动重试(如果适用)

package main

import (
    "bytes"
    "encoding/json"
    "net/http"
    "time"
    "crypto/tls"
)

func main() {
    // 创建自定义传输层配置
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true, // 仅用于测试环境
        },
        MaxIdleConns:        10,
        IdleConnTimeout:     30 * time.Second,
        DisableCompression:  true,
        // 禁用HTTP/2的自动重试
        TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
    }
    
    client := &http.Client{
        Transport: tr,
        Timeout:   30 * time.Second,
    }
    
    jvalues := map[string]interface{}{
        "text": "Hello, Slack!",
    }
    
    jsonValue, _ := json.Marshal(jvalues)
    
    req, err := http.NewRequest("POST", "http://posturl", bytes.NewBuffer(jsonValue))
    if err != nil {
        // 处理错误
        return
    }
    
    req.Header.Set("Content-Type", "application/json")
    
    response, err := client.Do(req)
    if err != nil {
        // 处理错误
        return
    }
    defer response.Body.Close()
}

3. 使用context控制请求生命周期

package main

import (
    "bytes"
    "context"
    "encoding/json"
    "net/http"
    "time"
)

func main() {
    // 创建context,设置超时
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()
    
    jvalues := map[string]interface{}{
        "text": "Hello, Slack!",
    }
    
    jsonValue, _ := json.Marshal(jvalues)
    
    req, err := http.NewRequestWithContext(ctx, "POST", "http://posturl", bytes.NewBuffer(jsonValue))
    if err != nil {
        // 处理错误
        return
    }
    
    req.Header.Set("Content-Type", "application/json")
    
    client := &http.Client{}
    response, err := client.Do(req)
    if err != nil {
        // 检查是否是超时错误
        if ctx.Err() == context.DeadlineExceeded {
            // 处理超时
        }
        return
    }
    defer response.Body.Close()
}

4. 添加重试控制逻辑

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "time"
)

func postWithRetryControl(url string, data interface{}, maxRetries int) (*http.Response, error) {
    client := &http.Client{
        Timeout: 60 * time.Second, // 设置较长的超时时间
    }
    
    jsonValue, _ := json.Marshal(data)
    
    for i := 0; i < maxRetries; i++ {
        req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonValue))
        if err != nil {
            return nil, err
        }
        
        req.Header.Set("Content-Type", "application/json")
        
        response, err := client.Do(req)
        if err != nil {
            if i == maxRetries-1 {
                return nil, err
            }
            // 等待后重试
            time.Sleep(time.Duration(i+1) * time.Second)
            continue
        }
        
        return response, nil
    }
    
    return nil, fmt.Errorf("max retries exceeded")
}

func main() {
    jvalues := map[string]interface{}{
        "text": "Hello, Slack!",
    }
    
    response, err := postWithRetryControl("http://posturl", jvalues, 1) // 只允许一次请求
    if err != nil {
        // 处理错误
        return
    }
    defer response.Body.Close()
}

关键点:

  1. 使用http.ClientTimeout字段设置合理的超时时间
  2. 避免使用默认的HTTP客户端,因为它有默认的超时设置
  3. 考虑使用context来控制请求的生命周期
  4. 如果确实需要重试机制,应该显式实现而不是依赖默认行为

对于Slack API调用,建议将超时时间设置为至少30秒,因为网络延迟和Slack服务器的响应时间可能会有波动。

回到顶部