事实证明人有的时候也不能太偷懒,太偷懒容易给自己埋坑。
问题的背景:
web端调用服务A,服务A异步调用服务B。服务A有四个场景需要调用服务B,所以,服务A中封装了一个公用的方法,唯一的区别是,场景不同时,发给服务B的body不相同,web端通过四个接口调用服务A,服务A组装body信息再调用服务B,只有一种场景报了下面的错误,这个错误看着像是域名解析的问题。但是,理论上不应该存在域名解析的错误,因为,从程序的逻辑看,因为调用B服务的方法是公用的,只有body不一样。
问题定位过程:
从控制变量的角度看,首先就是怀疑这个body有问题,通过postman,用同样的body测试了一下,没有问题,说明不会是body的问题。
只能考虑其他的问题。在web页面调用,然后把curl拷贝出来,直接导入postman测试。这种情况下,postman调用没有出问题。
比对了一下,web端调用的http请求的header和postman调用的http请求的header(虽然是复制过来的,但是,实际请求头还是发生了变化,postman做了处理)。
两者的User-Agent头不一样。
由此,可以推测,因为header导致了这个问题。
解决方案:
有了上面的推测,只要简单验证一下就可以了。由于原来的链路中,服务A请求服务B的过程中,header是直接复制了web端请求服务A时的header,所以,导致了这个问题。
所以,去掉这个复制header的操作,改为按照实际需求传header。
func SendRequest(ctx *gin.Context, url string, reqBody map[string]interface{}, header map[string]string) (string, error) {
var err error
req := &http.Request{}
defer func() {
if err != nil {
global.GIN_LOG.ErrorWithContext(ctx, err)
}
}()
//map转byte
reqBodyByte, err := json.Marshal(reqBody)
if err != nil {
return "", err
}
global.GIN_LOG.InfoWithContext(ctx, fmt.Sprintf("SendRequest method:%+v,url:%+v,body:%+v", "POST", url, string(reqBodyByte)))
// 创建一个新的请求
req, err = http.NewRequest("POST", url, strings.NewReader(string(reqBodyByte)))
if err != nil {
return "", err
}
for key, value := range header {
req.Header.Set(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
global.GIN_LOG.InfoWithContext(ctx, fmt.Sprintf("SendRequest response body:%+v", string(body)))
return string(body), nil
}