首次使用Go调用股票API,多ticker请求返回体被截断求助
多Ticker股票API返回解析不全问题的解决方案
核心问题
你的JSON解析中途失败,导致看起来返回体被截断,实际原因是:
ResponseData结构体中ExchangeShort、ExchangeLong被定义为bool类型,但API返回的是null,Go的基础类型bool无法解析JSON的null值,解析到第二个对象时触发错误,终止了解析流程。MarketCap字段同样被定义为float64,但API返回null,也会导致解析失败。PreviousCloseTime的JSON标签与API返回的键名不匹配(API返回previous_close_price_time,但标签写的是previous_close_time)。
修复步骤
- 修正结构体字段类型:将接受
null的字段改为指针类型,允许解析null值。 - 修正JSON标签:确保标签与API返回的键名完全一致。
- 完善错误处理:不要忽略任何错误,便于排查问题。
修改后的结构体定义
import "time" type Stock struct { Name string `json:"name"` Ticker string `json:"ticker"` Price float64 `json:"price"` DayHigh float64 `json:"day_high"` DayLow float64 `json:"day_low"` DayOpen float64 `json:"day_open"` DayChange float64 `json:"day_change"` PreviousClosePrice float64 `json:"previous_close_price"` } type ApiResponseStockData struct { ResponseStockData []ResponseData `json:"data"` } type ResponseData struct { Name string `json:"name"` Ticker string `json:"ticker"` ExchangeShort *bool `json:"exchange_short"` // 改为指针类型,支持null ExchangeLong *bool `json:"exchange_long"` // 改为指针类型,支持null MicCode string `json:"mic_code"` Currency string `json:"currency"` Price float64 `json:"price"` DayHigh float64 `json:"day_high"` DayLow float64 `json:"day_low"` DayOpen float64 `json:"day_open"` DayChange float64 `json:"day_change"` YearHigh float64 `json:"52_week_high"` YearLow float64 `json:"52_week_low"` MarketCap *float64 `json:"market_cap"` // 改为指针类型,支持null PreviousClosePrice float64 `json:"previous_close_price"` PreviousCloseTime time.Time `json:"previous_close_price_time"` // 修正标签匹配API键名 Volume float64 `json:"volume"` IsExtendedHoursPrice bool `json:"is_extended_hours_price"` LastTradeTime time.Time `json:"last_trade_time"` }
修改后的请求解析函数
import ( "fmt" "io" "net/http" "net/url" "encoding/json" ) func getStockPriceData(ticker string) ([]Stock, error) { baseURL, err := url.Parse("https://api.stockdata.org") if err != nil { return nil, fmt.Errorf("解析基础URL失败: %w", err) } baseURL.Path += "/v1/data/quote" // 补充斜杠,避免路径拼接错误 params := url.Values{} params.Add("symbols", ticker) params.Add("api_token", apiToken.ApiToken) baseURL.RawQuery = params.Encode() req, err := http.NewRequest("GET", baseURL.String(), nil) if err != nil { return nil, fmt.Errorf("创建请求失败: %w", err) } res, err := http.DefaultClient.Do(req) if err != nil { return nil, fmt.Errorf("发送请求失败: %w", err) } defer res.Body.Close() // 检查响应状态码,排除API错误 if res.StatusCode < 200 || res.StatusCode >= 300 { return nil, fmt.Errorf("API返回错误状态码: %s", res.Status) } body, err := io.ReadAll(res.Body) if err != nil { return nil, fmt.Errorf("读取响应体失败: %w", err) } apiResponseData := ApiResponseStockData{} err = json.Unmarshal(body, &apiResponseData) if err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } stocks := []Stock{} for _, data := range apiResponseData.ResponseStockData { stock := Stock{ Name: data.Name, Ticker: data.Ticker, Price: data.Price, DayHigh: data.DayHigh, DayLow: data.DayLow, DayOpen: data.DayOpen, PreviousClosePrice: data.PreviousClosePrice, DayChange: data.DayChange, } stocks = append(stocks, stock) } return stocks, nil }
额外说明
- 指针类型在Go中可以接受JSON的
null值,解析时会将null转换为nil。 - 完善错误处理后,后续遇到问题可以直接通过错误信息定位原因,避免像之前一样忽略错误导致排查困难。
- 路径拼接时补充斜杠是为了避免出现
https://api.stockdata.orgv1/data/quote这类错误URL。
内容的提问来源于stack exchange,提问作者Niall
相关产品推荐
相关产品推荐

