Go调用API无法读取完整响应体导致JSON解析失败问题求助
问题根因
- 主动丢弃读响应错误:代码中
body, _ := ioutil.ReadAll(resp.Body)使用_忽略了读取操作的所有报错,网络波动、连接提前断开、服务端中断传输等异常都会被掩盖,最终仅能拿到不完整的响应字节 - HTTP客户端无超时限制:零值初始化的
http.Client{}未配置任何超时阈值,弱网或服务端异常时连接中断不会触发错误回调,ReadAll会直接返回当前已读取的部分内容 - 潜在服务端/代理问题:可额外校验响应头的
Content-Length值是否和实际读取的字节长度一致,部分反向代理配置异常可能会主动截断响应内容
修复方案
- 禁止忽略所有操作的返回错误,读取响应、JSON解析环节的错误必须捕获处理
- 给HTTP客户端配置合理的超时时间,避免无限等待异常连接
- 可直接使用
json.Decoder从响应流直接解码,减少中间字节处理环节,也可以读取完成后校验Content-Length确保响应完整
修复后代码示例
var reqBody = []byte(fmt.Sprintf(`{ "methodName": "GetPropertyList", "params": { "token_key": "%v", "token_secret": "%v" } }`, token, secret)) req, err := http.NewRequest("POST", proxy_url, bytes.NewBuffer(reqBody)) if err != nil { log.Printf("创建请求失败: %v", err) return } req.Header.Set("Content-Type", "application/json") // 配置客户端超时,可根据业务调整时长 client := http.Client{ Timeout: 30 * time.Second, } resp, err := client.Do(req) if err != nil { log.Printf("发起请求失败: %v", err) return } defer resp.Body.Close() // 方案1:先读全再解析,保留错误检查 body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("读取响应失败: %v", err) return } log.Printf("BODY长度: %d,预期长度: %s", len(body), resp.Header.Get("Content-Length")) var respModel ResponseModel err = json.Unmarshal(body, &respModel) if err != nil { log.Printf("JSON解析失败,响应内容: %s,错误: %v", string(body), err) return } // 方案2:直接用Decoder从流解析,代码更简洁 // var respModel ResponseModel // err = json.NewDecoder(resp.Body).Decode(&respModel) // if err != nil { // log.Printf("响应解析失败: %v", err) // return // }
内容的提问来源于stack exchange,提问作者hobberwickey
相关产品推荐
相关产品推荐

