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

项目开发问题:需实现每5分钟仅调用一次机场API接口

实现机场数据每5分钟仅获取一次的解决方案

Hey there! Let's fix your problem of ensuring your airport data is only fetched from the external API once every 5 minutes. The core idea here is to cache the retrieved data and check if enough time has passed before making a new API call. I'll walk you through two common approaches depending on your project type.


1. 使用ASP.NET Core的IMemoryCache(推荐Web项目)

If you're working with an ASP.NET Core app, leveraging the built-in IMemoryCache is clean and maintainable. We'll inject it along with IHttpClientFactory (a better practice than directly instantiating HttpClient) to manage our requests and caching.

完整代码示例

using Microsoft.Extensions.Caching.Memory;
using System.Net.Http.Json;

public class AirportService
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IMemoryCache _memoryCache;
    private readonly string _airportApiUrl = @"https://raw.githubusercontent.com/jbrooksuk/JSON-Airports/master/airports.json";
    private const string _cacheKey = "AirportListCache";
    private static readonly TimeSpan _cacheExpiry = TimeSpan.FromMinutes(5);

    // 通过构造函数注入依赖
    public AirportService(IHttpClientFactory httpClientFactory, IMemoryCache memoryCache)
    {
        _httpClientFactory = httpClientFactory;
        _memoryCache = memoryCache;
    }

    public async Task<IEnumerable<Airport>> GetAirportData()
    {
        // 先尝试从缓存读取数据
        if (_memoryCache.TryGetValue(_cacheKey, out IEnumerable<Airport> cachedAirports))
        {
            return cachedAirports;
        }

        // 缓存不存在/已过期,调用API获取新数据
        var httpClient = _httpClientFactory.CreateClient();
        var response = await httpClient.GetAsync(_airportApiUrl);
        response.EnsureSuccessStatusCode(); // 确保请求成功,否则抛出HttpRequestException

        var airports = await response.Content.ReadFromJsonAsync<IEnumerable<Airport>>();

        // 将新数据存入缓存,并设置5分钟过期时间
        var cacheOptions = new MemoryCacheEntryOptions()
            .SetAbsoluteExpiration(_cacheExpiry); // 绝对过期:从存入时间开始算5分钟后过期

        _memoryCache.Set(_cacheKey, airports, cacheOptions);

        return airports;
    }
}

关键说明

  • IHttpClientFactory: Manages HttpClient instances efficiently, avoiding issues with socket exhaustion.
  • IMemoryCache: Handles caching automatically, including expiration. We use SetAbsoluteExpiration to ensure the cache is refreshed exactly every 5 minutes.
  • Cache Check: The first thing the method does is check the cache—if data exists and isn't expired, it returns immediately without hitting the API.

2. 手动实现缓存(适合非Web项目,如控制台/桌面应用)

If you're not using ASP.NET Core, you can manually maintain a cache with a timestamp and thread-safe locks to prevent concurrent API calls.

完整代码示例

using System.Text.Json;

public class AirportService
{
    private readonly HttpClient _httpClient;
    private readonly string _airportApiUrl = @"https://raw.githubusercontent.com/jbrooksuk/JSON-Airports/master/airports.json";
    private IEnumerable<Airport> _cachedAirports;
    private DateTime _lastFetchTime = DateTime.MinValue;
    private static readonly TimeSpan _refreshInterval = TimeSpan.FromMinutes(5);
    private readonly object _lockObject = new(); // 线程安全锁,防止多线程下重复请求

    public AirportService()
    {
        _httpClient = new HttpClient();
    }

    public async Task<IEnumerable<Airport>> GetAirportData()
    {
        // 检查缓存是否有效
        lock (_lockObject)
        {
            if (_cachedAirports != null && DateTime.Now - _lastFetchTime < _refreshInterval)
            {
                return _cachedAirports;
            }
        }

        try
        {
            // 请求API获取新数据
            var response = await _httpClient.GetAsync(_airportApiUrl);
            response.EnsureSuccessStatusCode();

            var stream = await response.Content.ReadAsStreamAsync();
            var airports = await JsonSerializer.DeserializeAsync<IEnumerable<Airport>>(stream);

            // 更新缓存和时间戳(加锁保证线程安全)
            lock (_lockObject)
            {
                _cachedAirports = airports;
                _lastFetchTime = DateTime.Now;
            }

            return airports;
        }
        catch (Exception ex)
        {
            // 可选:记录异常日志
            // 如果API请求失败,返回旧缓存(如果存在),避免服务中断
            lock (_lockObject)
            {
                if (_cachedAirports != null)
                {
                    return _cachedAirports;
                }
            }
            // 没有旧缓存时,抛出异常(根据业务需求调整)
            throw new InvalidOperationException("Failed to fetch airport data and no cached data available.", ex);
        }
    }
}

关键说明

  • Thread Safety: The lock statements ensure that only one thread can check/update the cache at a time, preventing multiple concurrent API calls when the cache expires.
  • Fallback Logic: If the API request fails, we return the last cached data (if available) to keep your application functional.
  • Manual Expiry Check: We compare the current time to _lastFetchTime to determine if a new API call is needed.

额外优化建议

  • Add Retry Logic: Use libraries like Polly to add retry policies for transient API failures (e.g., network timeouts).
  • Sliding Expiration: If you want the cache to refresh only after 5 minutes of inactivity (instead of a fixed interval), use SetSlidingExpiration with IMemoryCache.
  • Cache Persistence: For long-running apps, consider using a distributed cache (like Redis) instead of in-memory cache to avoid losing data when the app restarts.

内容的提问来源于stack exchange,提问作者pmt665

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:33:36