HttpClient 在服务器上启用缓存

Esb*_*sen 2 .net caching asp.net-web-api dotnet-httpclient

我正在尝试启用 System.Net.HttpClient 的客户端缓存。我在http://localhost:83/api/test有一个端点,它需要 1 秒的时间来响应并将缓存标头发回。

如果我有这个代码

static async Task MainAsync()
{
    var client = new HttpClient(new WebRequestHandler { CachePolicy = new HttpRequestCachePolicy() }) { BaseAddress = new Uri("http://localhost:83/api/") };
    for (int i = 0; i < 20; i++)
    {
        var response = await client.GetAsync("test");
        var res = await response.Content.ReadAsStringAsync();
        Console.WriteLine(res);
    }
}
Run Code Online (Sandbox Code Playgroud)

执行需要一秒钟。

如果我将相同的代码放入 api 控制器

    static HttpClient client = new HttpClient(new WebRequestHandler {CachePolicy = new HttpRequestCachePolicy() }) { BaseAddress = new Uri("http://localhost:83/api/") };
    public async Task<string> Get()
    {
        for (int i = 0; i < 20; i++)
        {
            var response = await client.GetAsync("test");
            var res = await response.Content.ReadAsStringAsync();
        }
        return "ok";
    }
Run Code Online (Sandbox Code Playgroud)

并将其托管在 IIS 中需要 20 秒才能响应。

我需要做什么才能从服务器应用程序启用客户端缓存?

Leo*_*lev 5

可能您应该切换到 WinHTTP 并使用另一个 HTTP 缓存实现。

.NET Framework 使用两个 HTTP 客户端 API。一个由 WinINet 提供,另一个由 WinHTTP 提供。.NET Framework 默认使用 WinINet。但是 WinINet 是为在客户端应用程序中工作而开发的,它不应该在服务器环境中工作。MSDN 上Windows Internet页面的相关引用:

在适用的情况下

WinINet 不支持服务器实现。此外,不应从服务中使用它。对于服务器实现或服务,请使用Microsoft Windows HTTP 服务 (WinHTTP)

因此,在您的 Web API 中,您需要使用 WinHTTP。我知道切换的唯一方法是WinHttpHandlerSystem.Net.Http.WinHttpHandler NuGet 包中使用。但是目前这个处理程序不使用 HTTP 缓存。它无法设置缓存策略,并且会忽略所有相关设置HttpClientHandler。请参阅如何通过 WinHttpHandler 和 HttpClient 使用 HTTP 缓存?GitHub 上的问题。

要解决此问题,您可以实现自己的缓存机制或使用现有的缓存机制,如CacheCow项目。它具有内置的内存存储和自己的DelagatingHandlerfor实现HttpClient。请注意,目前存在一些兼容性问题,在安装 System.Net.Http.WinHttpHandler 和 CacheCow.Clien NuGet 包之前,您需要从 Web API 项目中手动删除对 .NET Framework System.Net.Http 的引用。以下截取的代码演示了 CacheCow.Clien NuGet 包的用法WinHttpHandlerCachingHandler样例:

static HttpClient client = new HttpClient(new CachingHandler { InnerHandler = new WinHttpHandler() })
{
    BaseAddress = new Uri("http://localhost:83/api/")
};
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请检查: