Go调用外汇JSON API时,如何正确处理返回类型与错误?
处理API响应的两种格式:正常报价 vs 错误消息
在Go里处理这种同一API可能返回两种不同格式响应的情况,核心思路是调整函数的返回值,让它既能返回正常的报价数据,也能传递错误信息——这也是Go语言处理这类场景的惯用做法。下面给你一步步拆解解决方案:
1. 明确错误响应格式并定义对应类型
首先得对应API的错误返回格式:你提到返回的是类似"The data you've requested is not available"的内容,分两种情况处理:
- 如果是纯JSON字符串(响应体直接是
"xxx"):直接用string类型解析; - 如果是JSON对象(比如
{"message": "xxx"}):定义对应的结构体。
我们先按纯字符串错误来演示,后续可以根据实际API格式调整。
2. 修改GetQuotes的返回值类型
原来的函数只返回[]Quote,没法传递错误信息,所以要改成返回结果+错误的组合:([]Quote, error)。这样调用方可以通过判断error是否为nil来区分成功/失败分支。
3. 实现双重解析逻辑
先尝试把响应解析为正常的[]Quote,如果失败,再尝试解析为错误消息,最后把错误包装成Go标准的error类型返回。
完整代码示例:
import ( "encoding/json" "fmt" "log" "strings" "net/http" "io" ) type Quote struct { Symbol string `json:"symbol"` Bid float32 `json:"bid"` Ask float32 `json:"ask"` Price float32 `json:"price"` Timestamp int `json:"timestamp"` } func GetQuotes(symbols []string, apiKey string) ([]Quote, error) { // 调用fetch获取API响应 result, err := fetch("quotes?pairs=" + strings.Join(symbols, ","), apiKey) if err != nil { return nil, fmt.Errorf("failed to fetch data: %w", err) } // 第一步:尝试解析为正常的报价数组 var quotes []Quote if parseErr := json.Unmarshal(result, "es); parseErr == nil { return quotes, nil } // 第二步:解析失败,尝试解析为错误字符串 var errorMsg string if parseErr := json.Unmarshal(result, &errorMsg); parseErr == nil { return nil, fmt.Errorf("api error: %s", errorMsg) } // 第三步:两种解析都失败,返回原始错误 return nil, fmt.Errorf("failed to parse response: %w", parseErr) } // 优化后的fetch函数:先检查HTTP状态码,提前拦截错误 func fetch(endpoint string, apiKey string) ([]byte, error) { req, err := http.NewRequest("GET", "https://your-api-domain.com/"+endpoint, nil) if err != nil { return nil, err } req.Header.Set("API-Key", apiKey) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // 先检查状态码,非2xx直接判定为错误 if resp.StatusCode < 200 || resp.StatusCode >= 300 { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("api returned status %d: %s", resp.StatusCode, string(body)) } body, err := io.ReadAll(resp.Body) return body, err }
为什么不推荐用json.RawMessage直接返回?
你提到用json.RawMessage后没法设置合适的返回类型——这是因为RawMessage本质是字节数组,调用方拿到后还得自己做二次解析,违背了函数封装的原则。而返回([]Quote, error)的方式更符合Go的错误处理习惯,调用方可以清晰处理分支:
quotes, err := GetQuotes([]string{"EURUSD", "GBPUSD"}, "your-api-key") if err != nil { log.Printf("Failed to get quotes: %v", err) // 这里可以做错误转发、日志记录等操作 return } // 处理正常报价数据 for _, q := range quotes { fmt.Printf("Symbol: %s, Price: %.2f\n", q.Symbol, q.Price) }
额外优化建议
如果API返回的错误是JSON对象(比如{"error": "xxx"}),只需要替换错误解析的类型即可:
type APIError struct { Error string `json:"error"` } // 在GetQuotes里替换错误解析逻辑 var apiErr APIError if parseErr := json.Unmarshal(result, &apiErr); parseErr == nil { return nil, fmt.Errorf("api error: %s", apiErr.Error) }
内容的提问来源于stack exchange,提问作者Jacob Davis
相关产品推荐
相关产品推荐

