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()
}
关键点:
- 使用
http.Client的Timeout字段设置合理的超时时间 - 避免使用默认的HTTP客户端,因为它有默认的超时设置
- 考虑使用context来控制请求的生命周期
- 如果确实需要重试机制,应该显式实现而不是依赖默认行为
对于Slack API调用,建议将超时时间设置为至少30秒,因为网络延迟和Slack服务器的响应时间可能会有波动。

