使用Golang和OpenWeather API构建天气应用

使用Golang和OpenWeather API构建天气应用 我最近撰写了一份详细的指南,介绍如何使用 OpenWeather API 在 Go 语言中构建一个天气应用程序。内容涵盖了进行 API 调用、解析 JSON 数据以及展示结果。如果你感兴趣,这里是链接:使用 OpenWeather API 在 Go 中构建天气应用程序。我很想听听你的反馈!

2 回复

这非常酷且实用。感谢您的付出!blush

更多关于使用Golang和OpenWeather API构建天气应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


关于使用Golang和OpenWeather API构建天气应用的评论

看了你的教程,实现得很完整!这里我补充几个实际开发中可能会用到的优化点和技术细节:

1. 使用结构体标签处理JSON字段命名差异

OpenWeather API返回的字段有时使用蛇形命名法,而Go习惯使用驼峰式。可以通过结构体标签优雅处理:

type WeatherResponse struct {
    Coord struct {
        Lon float64 `json:"lon"`
        Lat float64 `json:"lat"`
    } `json:"coord"`
    Main struct {
        Temp      float64 `json:"temp"`
        FeelsLike float64 `json:"feels_like"`
        TempMin   float64 `json:"temp_min"`
        TempMax   float64 `json:"temp_max"`
        Pressure  int     `json:"pressure"`
        Humidity  int     `json:"humidity"`
    } `json:"main"`
    Name string `json:"name"`
}

2. 添加请求超时和重试机制

生产环境中需要更健壮的HTTP客户端:

func fetchWeatherData(apiKey, city string) (*WeatherResponse, error) {
    client := &http.Client{
        Timeout: 10 * time.Second,
    }
    
    url := fmt.Sprintf(
        "https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric",
        city, apiKey,
    )
    
    // 重试逻辑
    var resp *http.Response
    var err error
    
    for i := 0; i < 3; i++ {
        resp, err = client.Get(url)
        if err == nil && resp.StatusCode == 200 {
            break
        }
        time.Sleep(time.Duration(i+1) * time.Second) // 指数退避
    }
    
    if err != nil {
        return nil, fmt.Errorf("请求失败: %v", err)
    }
    defer resp.Body.Close()
    
    // 解析响应...
}

3. 使用context控制请求生命周期

特别是需要处理用户取消请求的场景:

func fetchWeatherWithContext(ctx context.Context, apiKey, city string) (*WeatherResponse, error) {
    req, err := http.NewRequestWithContext(
        ctx, 
        "GET", 
        fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s", city, apiKey),
        nil,
    )
    if err != nil {
        return nil, err
    }
    
    client := &http.Client{Timeout: 5 * time.Second}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    // 解析响应...
}

4. 添加响应缓存减少API调用

对于天气数据这种变化不频繁的内容,可以添加本地缓存:

type WeatherCache struct {
    data map[string]WeatherCacheEntry
    mu   sync.RWMutex
}

type WeatherCacheEntry struct {
    data      *WeatherResponse
    timestamp time.Time
}

func (c *WeatherCache) Get(city string) (*WeatherResponse, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    
    entry, exists := c.data[city]
    if !exists {
        return nil, false
    }
    
    // 缓存10分钟
    if time.Since(entry.timestamp) > 10*time.Minute {
        return nil, false
    }
    
    return entry.data, true
}

5. 错误处理的完整示例

更全面的错误处理可以提升用户体验:

func getWeather(apiKey, city string) error {
    weather, err := fetchWeatherData(apiKey, city)
    if err != nil {
        if strings.Contains(err.Error(), "timeout") {
            return fmt.Errorf("请求超时,请检查网络连接")
        }
        if strings.Contains(err.Error(), "404") {
            return fmt.Errorf("城市 '%s' 未找到", city)
        }
        if strings.Contains(err.Error(), "401") {
            return fmt.Errorf("API密钥无效")
        }
        return fmt.Errorf("获取天气数据失败: %v", err)
    }
    
    // 处理数据...
    return nil
}

你的教程涵盖了核心流程,这些补充内容可以帮助开发者构建更健壮的生产级应用。特别是错误处理和缓存机制,在实际部署中非常重要。

回到顶部