You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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, &quotes); 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:47:54