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

IHostedService中通过HttpClient请求swagger.json超时如何解决?

问题根因
  • 你现在的写法触发了ASP.NET Core启动流程的时序问题:IHostedService.StartAsync的执行阶段早于Kestrel服务器启动端口监听的阶段,此时向本地端口发送HTTP请求,当前应用本身还没做好接收请求的准备,请求无法得到响应,最终触发超时报错。
最优解决方案(针对获取当前应用自身的swagger.json场景)

完全不需要发起HTTP请求,直接调用Swagger内置的文档生成器在本地生成文档即可,避免跨网络请求的开销和时序问题,注意需要提前安装Swashbuckle.AspNetCoreNuget包,引用Swashbuckle.AspNetCore.Swagger命名空间即可使用ISwaggerProvider,修改后的代码如下:

public class InitializeCacheService : IHostedService
{
    private readonly IMemoryCache _cache;
    public static readonly string SwaggerJsonCacheKey = "swagger.json";
    private readonly ISwaggerProvider _swaggerProvider;
    private readonly IServiceProvider _serviceProvider;

    public InitializeCacheService(IMemoryCache cache, ISwaggerProvider swaggerProvider, IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
        _swaggerProvider = swaggerProvider;
        _cache = cache;
    }
    public Task StartAsync(CancellationToken cancellationToken)
    {
        if (!_cache.TryGetValue(SwaggerJsonCacheKey, out SwaggerDocumentCache cacheEntry))
        {
            // 直接本地生成v1版本的swagger文档,不需要发HTTP请求
            var swaggerDoc = _swaggerProvider.GetSwagger("v1");
            
            // 转成你需要的SwaggerDocumentCache格式即可,示例用System.Text.Json序列化
            var json = JsonSerializer.Serialize(swaggerDoc);
            cacheEntry = JsonSerializer.Deserialize<SwaggerDocumentCache>(json);
            
            // 建议根据实际需求调整过期时间,3秒过期太频繁会导致频繁生成
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                  .SetSlidingExpiration(TimeSpan.FromHours(24));

            _cache.Set(SwaggerJsonCacheKey, cacheEntry, cacheEntryOptions);
        }
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}
如果你确实需要通过HTTP请求获取swagger文档(比如目标是外部服务)

不要阻塞应用启动流程,将加载逻辑放到后台异步执行,等待应用完全启动后再执行,示例如下:

public class InitializeCacheService : IHostedService
{
    private IMemoryCache _cache;
    public static readonly string swaggerJson = "swagger.json";
    private readonly HttpClient _httpClient;
    private readonly IServiceProvider _serviceProvider;
    private readonly IHostApplicationLifetime _appLifetime;

    public InitializeCacheService(IMemoryCache cache, HttpClient client, IServiceProvider serviceProvider, IHostApplicationLifetime appLifetime)
    {
        _serviceProvider = serviceProvider;
        _httpClient = client;
        _cache = cache;
        _appLifetime = appLifetime;
    }
    public Task StartAsync(CancellationToken cancellationToken)
    {
        // 注册应用启动完成后的回调,此时Kestrel已经开始监听端口
        _appLifetime.ApplicationStarted.Register(async () =>
        {
            if (!_cache.TryGetValue(swaggerJson, out SwaggerDocumentCache cacheEntry))
            {
                _httpClient.BaseAddress = new Uri("https://localhost:44397");
                var response = await _httpClient.GetAsync("swagger/v1/swagger.json", cancellationToken);
                response.EnsureSuccessStatusCode();
                using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
                cacheEntry = await JsonSerializer.DeserializeAsync<SwaggerDocumentCache>(responseStream, cancellationToken: cancellationToken);
                var cacheEntryOptions = new MemoryCacheEntryOptions()
                      .SetSlidingExpiration(TimeSpan.FromHours(24));
                _cache.Set(swaggerJson, cacheEntry, cacheEntryOptions);
            }
        });
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 10:21:03