导读:本期聚焦于半夏创作的《Golang如何开发天气查询应用?从API调用到命令行工具实战详解》,敬请观看详情。想用Go语言写一个能查天气的小工具,却不知道从哪里下手?本文手把手带你完成一个完整的天气查询应用:先讲清楚如何挑选合适的天气数据源以及申请API密钥,再用标准库和第三方库两种方式实现HTTP请求,详细处理JSON响应的解析与错误场景,最后把程序封装成一个支持多城市查询的命令行工具,并介绍缓存、超时控制、并发查询等进阶技巧。文中代码均可直接运行,适合刚学完Go基础语法想动手做项目的读者参考。

用Go做一个小工具练手,天气查询是再合适不过的选择:它涉及网络请求、JSON解析、命令行参数处理、错误兜底这些日常开发中最常见的技能点,业务逻辑又不复杂,非常适合作为入门后的第一个完整项目。这篇文章带你从零开始实现一个可用的天气查询命令行工具,最后还会加上缓存和并发查询的能力,让它看起来更像一个正经的工程项目。

Golang如何开发天气查询应用?从API调用到命令行工具实战详解

一、选择天气数据源并申请API密钥

开发天气应用的第一步是确定数据从哪来。目前国内外可选的天气API不少,国外常用的是OpenWeatherMap和WeatherAPI,国内可以用和风天气或者心知天气。对练手项目来说,OpenWeatherMap的免费额度完全够用,注册账号后到控制台创建一个API Key就能直接调用,这里以它为例讲解。

拿到密钥后先别急着写代码,用浏览器或者curl手动请求一次接口,确认返回的数据结构长什么样。以查询北京天气为例,请求地址是https://api.openweathermap.org/data/2.5/weather?q=Beijing&appid=你的密钥&units=metric&lang=zh_cn,其中units=metric表示使用摄氏度,lang=zh_cn让描述字段返回中文。返回的JSON里包含城市名、坐标、温度、湿度、风速、天气描述等信息,把这些字段摸清楚,后面定义结构体就心里有数了。

有一点要提前注意:密钥属于敏感信息,不要直接写死在代码里提交到仓库。推荐的做法是通过环境变量传入,比如os.Getenv("OPENWEATHER_API_KEY"),这样换一台机器或者换一个密钥都不用改代码。

二、实现HTTP请求与JSON解析

Go标准库的net/httpencoding/json已经足够完成整个请求解析流程,不需要引入任何第三方依赖。先定义一个与返回JSON对应的结构体,字段名用大写开头,加上json标签做映射。不需要的字段直接省略,Go会自动忽略JSON里多余的内容。

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

// WeatherResult 对应接口返回的JSON结构,只取需要的字段
type WeatherResult struct {
	Name string `json:"name"`
	Main struct {
		Temp     float64 `json:"temp"`
		Humidity int     `json:"humidity"`
	} `json:"main"`
	Weather []struct {
		Description string `json:"description"`
	} `json:"weather"`
}

func fetchWeather(city, apiKey string) (*WeatherResult, error) {
	url := fmt.Sprintf(
		"https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric&lang=zh_cn",
		city, apiKey,
	)
	resp, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %w", err)
	}
	defer resp.Body.Close()

	// 接口返回非200时读取错误信息
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("接口返回状态码 %d", resp.StatusCode)
	}

	var result WeatherResult
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("解析JSON失败: %w", err)
	}
	return &result, nil
}

这段代码有几个值得留意的细节。第一,defer resp.Body.Close()必须写,否则高频调用会泄漏连接;第二,用json.NewDecoder(resp.Body).Decode直接从流解析,比先读完再json.Unmarshal更省内存;第三,错误用%w包装,调用方可以用errors.Iserrors.As逐层判断原因。

城市名如果包含中文或空格,直接拼到URL里会出问题,应该用net/url包做一次转义:url.QueryEscape(city),这样「hang zhou」这类输入也能正确处理。另外生产环境不建议用默认的http.Get,它没有超时控制,一旦对端服务卡住,你的程序也会跟着挂起,后面进阶部分会给出带超时的写法。

三、封装成命令行工具

解析逻辑写好后,接下来把它包装成一个好用的命令行程序。Go标准库的flag包就能满足需求,支持-city指定城市、-days指定天数之类的参数,不需要额外安装依赖。

package main

import (
	"flag"
	"fmt"
	"os"
)

func main() {
	city := flag.String("city", "beijing", "要查询的城市名")
	flag.Parse()

	apiKey := os.Getenv("OPENWEATHER_API_KEY")
	if apiKey == "" {
		fmt.Fprintln(os.Stderr, "请先设置环境变量 OPENWEATHER_API_KEY")
		os.Exit(1)
	}

	result, err := fetchWeather(*city, apiKey)
	if err != nil {
		fmt.Fprintln(os.Stderr, "查询失败:", err)
		os.Exit(1)
	}

	desc := ""
	if len(result.Weather) > 0 {
		desc = result.Weather[0].Description
	}
	fmt.Printf("城市: %s\n温度: %.1f℃\n湿度: %d%%\n天气: %s\n",
		result.Name, result.Main.Temp, result.Main.Humidity, desc)
}

运行方式是go build -o weather.exe main.go,然后执行./weather.exe -city=shanghai就能看到输出。如果想同时查多个城市,把flag.Args()剩下的参数都取出来循环查询即可。如果后续参数越来越复杂,比如要支持子命令,可以换成cobra这样的第三方库,它就是Docker和Kubernetes CLI底层用的框架。

输出格式也可以做得更友好。Windows的终端默认不支持UTF-8时中文可能乱码,可以提醒用户执行chcp 65001切换编码;Linux和macOS下一般没有这个问题。颜色输出可以用golang.org/x/term或者直接输出ANSI转义序列,让温度用不同颜色区分冷暖。

四、进阶优化:超时、缓存与并发

基础版能跑之后,可以从三个方向把它变得健壮。首先是超时控制,自己构造一个带超时的http.Client,替代全局的默认Client:

var httpClient = &http.Client{
	Timeout: 5 * time.Second,
}

其次是缓存。天气数据变化不快,同一座城市短时间内重复查询完全没必要每次都打接口,用一个带过期时间的map就能实现简单缓存,或者直接用go-cache这个库,几行代码搞定。缓存不仅能加快响应速度,还能避免免费额度被快速耗尽。

最后是并发查询。当需要一次查多个城市时,串行循环会非常慢,用goroutine配合sync.WaitGroup并行发起请求,总耗时约等于最慢的那一次请求。要注意结果收集不能直接往共享map里写,应该通过channel回传或者用sync.Mutex保护,初学者最容易在这里踩到数据竞争的坑,可以用go run -race检测。经过这三步优化,这个小工具就具备了实际可用的工程素质,后续还可以加上Web接口或者定时推送,把它扩展成一个完整的天气服务。

Golang天气查询REST API修改时间:2026-09-03 15:55:02

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260903/49660.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。