在 Golang 中构建一个股票行情查询程序,核心思路是通过标准库发起 HTTP 请求,调用公开或自建的行情接口,将返回的 JSON 数据解析为结构体,再以清晰格式输出给用户。这种方式不依赖外部框架,编译后单一可执行文件即可运行,非常适合编写轻量级命令行工具。

一、项目结构与依赖准备
我们先规划一个最简单的项目布局。由于 Golang 标准库已经提供了 net/http、encoding/json 等必要组件,因此无需引入第三方 HTTP 客户端。新建目录 stockquery,在内部创建 main.go 作为程序入口即可。
使用 Go Modules 管理依赖能保证构建可复现。在终端执行 go mod init stockquery 后,go 工具链会自动记录标准库引用。如果后续接入需要 OAuth 的行情服务商,再考虑添加 golang.org/x/oauth2 等扩展包,但基础查询用不到。
二、定义行情数据结构
不同服务商的 JSON 字段命名差异很大,因此要先明确我们关心哪些内容。通常股票行情至少包含代码、名称、当前价、昨收价与涨跌幅。我们在代码里用 struct 描述,并通过 json tag 映射原始字段。
下面示例假设接口返回的是平铺字段。如果接口嵌套了对象,比如 data.quote,则 struct 也要相应嵌套。合理的结构定义能避免解析时出现零值或类型不匹配的问题。
package main
import (
"encoding/json"
)
// StockQuote 表示单只股票的行情
type StockQuote struct {
Symbol string `json:"symbol"`
Name string `json:"name"`
Price float64 `json:"price"`
PrevClose float64 `json:"prev_close"`
ChangePercent float64 `json:"change_percent"`
}
// ApiResponse 是接口外层包装
type ApiResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data StockQuote `json:"data"`
}
三、发起 HTTP 请求并控制超时
网络调用必须设置超时,否则程序可能永久阻塞。net/http 的 Client 可以配置 Timeout 字段,这样无论是连接、发送还是读取 body,只要在设定时间内未完成就会返回错误。对于行情查询,建议超时设在 3 到 5 秒。
我们写一个函数 fetchQuote,接收股票代码,拼接请求地址,调用接口并解析。注意这里使用的示例域名是 ipipp.com,仅作演示,实际可替换为你的服务商地址。同时检查 HTTP 状态码,非 200 时直接报错,不要尝试解析错误页面。
package main
import (
"fmt"
"io"
"net/http"
"time"
)
func fetchQuote(symbol string) (*StockQuote, error) {
client := &http.Client{
Timeout: 4 * time.Second,
}
url := "https://api.ipipp.com/stock/quote?code=" + symbol
resp, err := client.Get(url)
if err != nil {
return nil, fmt.Errorf("请求失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("接口返回状态码 %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %w", err)
}
var apiResp ApiResponse
if err := json.Unmarshal(body, &apiResp); err != nil {
return nil, fmt.Errorf("JSON解析失败: %w", err)
}
if apiResp.Code != 0 {
return nil, fmt.Errorf("业务错误: %s", apiResp.Msg)
}
return &apiResp.Data, nil
}
四、格式化输出结果
拿到数据后,命令行程序应当以整齐方式呈现。除了简单 fmt.Printf,还可以用 text/tabwriter 让多列对齐,提升可读性。如果打算供其他系统消费,则直接输出 JSON 字符串更合适。
以下示例同时展示表格化打印与 JSON 输出两种模式。表格化适合人工查看,JSON 方便管道处理。你可以根据启动参数切换,也可以默认打印表格并在加 -j 参数时输出 JSON。
package main
import (
"encoding/json"
"fmt"
"os"
"text/tabwriter"
)
func printTable(q *StockQuote) {
w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0)
fmt.Fprintln(w, "代码t名称t现价t昨收t涨跌幅")
fmt.Fprintf(w, "%st%st%.2ft%.2ft%.2f%%n",
q.Symbol, q.Name, q.Price, q.PrevClose, q.ChangePercent)
w.Flush()
}
func printJSON(q *StockQuote) {
b, _ := json.MarshalIndent(q, "", " ")
fmt.Println(string(b))
}
五、组装 main 函数与运行测试
最后把上述部分连起来。main 函数读取命令行参数中的股票代码,调用 fetchQuote,再根据需求输出。若未传代码,给出简短用法提示。
编译后运行 ./stockquery sh600000 即可查询该股票。整个程序不到两百行,却完整覆盖了网络请求、超时、解析、输出等关键环节,可以作为更复杂行情系统的起点。
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("用法: stockquery 股票代码")
return
}
symbol := os.Args[1]
q, err := fetchQuote(symbol)
if err != nil {
fmt.Printf("查询出错: %vn", err)
return
}
printTable(q)
}
六、常见误区与改进方向
初学者常把 http.Get 当作全局复用客户端,实际上默认客户端无超时,高并发时会耗尽连接。始终显式声明带超时的 Client 是好习惯。另一个误区是忽略接口的业务 code 字段,只判断 HTTP 200,导致拿到错误数据还以为成功。
后续可加入本地缓存减少请求频次,或利用 goroutine 同时查多只股票。若接口需密钥,把 token 放在请求头而非 URL 中,避免泄露。这样你的 Golang 股票查询程序会更健壮也更易维护。