Go中API Handler调用第三方API后无法返回响应问题
问题分析与修复方案
1. 未正确关闭外部API响应的Body
在GetEvents方法中,调用o.client.Do(req)获取到resp后,既没有关闭resp.Body,也没有读取其中内容。Go的HTTP客户端依赖连接池复用连接,若不关闭响应Body,连接会被长期占用,最终导致连接池耗尽,后续向客户端发送响应时无法获取可用连接,表现为客户端收不到返回内容。
修复代码:
func (o *API) GetEvents(account string, startDate string, endDate string) ([]Event, error) { BaseUrl := "http://external-api.com" url := fmt.Sprintf("%s/v2/client/%s/event?startDate=%s&endDate=%s", BaseUrl, account, startDate, endDate) // 不要忽略请求创建错误 req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } // 确保结构体字段名大小写匹配(此处假设结构体字段为小写token/secret) req.Header.Add("token", o.token) req.Header.Add("secret", o.secret) resp, err := o.client.Do(req) if err != nil { return nil, err } // 必须延迟关闭响应Body defer resp.Body.Close() // 即使不需要响应内容,也要读取Body避免连接泄漏 _, err = io.Copy(io.Discard, resp.Body) if err != nil { return nil, err } // 检查外部API响应状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("external API returned status: %s", resp.Status) } fmt.Println(resp) return []Event{}, nil }
2. 忽略关键错误
原代码中http.NewRequest的错误被直接忽略(用_接收),若URL格式非法(比如account包含未转义的特殊字符),会导致请求失败但无法排查。必须显式处理该错误。
3. 结构体字段访问不匹配(潜在问题)
如果API结构体中的token/secret字段定义为小写(token string),但GetEvents中误写为o.Token(大写),会导致请求头中的认证信息为空,外部API可能返回错误响应。需确保字段名大小写完全一致。
4. 未校验外部API响应状态
即使client.Do()没有返回错误,外部API仍可能返回非200状态码(如401权限错误、404资源不存在),此时继续执行后续逻辑不符合预期,需添加状态码校验。
5. 强化sendJSON的错误处理
虽然你反馈未看到错误,但可以优化日志输出和异常处理,避免因Header已写入导致的错误:
func sendJSON(w http.ResponseWriter, status int, message string, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) err := json.NewEncoder(w).Encode(&APIResponse{ Status: status, Message: message, Data: data, }) if err != nil { // 使用标准日志库替代fmt.Println,便于排查问题 log.Printf("failed to encode response: %v", err) // 若已写入Header,直接输出错误JSON w.Write([]byte(fmt.Sprintf(`{"status":500,"message":"%s"}`, err.Error()))) return } }
验证步骤
修复后重新运行服务:
- 确认
GetEvents中正确关闭并读取了外部API的响应Body - 检查服务端日志,确认
sendJSON正常执行且无编码错误 - 验证外部API返回状态码为200
内容的提问来源于stack exchange,提问作者Limeoats
相关产品推荐
相关产品推荐

