【问题标题】:HttpClient enable cache on serverHttpClient 在服务器上启用缓存
【发布时间】:2017-12-08 13:10:13
【问题描述】:

我正在尝试启用 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);
    }
}

执行需要一秒钟。

如果我将相同的代码放入 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";
    }

在 IIS 中托管它需要 20 秒才能响应。

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

【问题讨论】:

    标签: .net caching asp.net-web-api dotnet-httpclient


    【解决方案1】:

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

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

    如适用

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

    因此,在您的 Web API 中,您需要使用 WinHTTP。我知道的唯一切换方法是使用来自System.Net.Http.WinHttpHandler NuGet 包的WinHttpHandler。但目前这个处理程序不使用 HTTP 缓存。它无法设置缓存策略,它会忽略HttpClientHandler 尊重的所有设置。请参阅 GitHub 上的 How do I utilize HTTP caching with WinHttpHandler and HttpClient? 问题。

    要解决此问题,您可以实现自己的缓存机制或使用现有的缓存机制,例如 CacheCow 项目。它有内置的内存存储和它自己的DelagatingHandler 实现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/")
    };
    

    更多信息请查看:

    【讨论】:

      【解决方案2】:

      运行您的网站的应用程序池没有与之关联的用户配置文件,或者配置文件中的某处禁止缓存。

      为了利用 IIS 中的缓存机制,您需要将用户配置文件与应用程序池相关联,以便您的网站可以利用该配置文件的临时文件夹。有关更多详细信息,请参阅 Chris Oldwood 的 IIS Hosted Web API Not Caching Internal HTTP Responses 文章。来自MSDN上Application Pool Identities页面的相关引用:

      用户个人资料

      IIS 不会加载 Windows 用户配置文件,但某些应用程序可能会利用它来存储临时数据。 SQL Express 是执行此操作的应用程序示例。但是,必须创建用户配置文件以将临时数据存储在配置文件目录或注册表配置单元中。网络服务帐户的用户配置文件由系统创建并且始终可用。但是,切换到唯一的应用程序池身份后,系统不会创建任何用户配置文件。只有标准应用程序池(DefaultAppPool 和 Classic .NET AppPool)在磁盘上有用户配置文件。如果管理员创建新的应用程序池,则不会创建用户配置文件。

      但是,如果需要,您可以通过将 LoadUserProfile 属性设置为“true”来配置 IIS 应用程序池以加载用户配置文件。

      嵌入式缓存机制也可以通过 web 或机器配置文件中的disableAllCaching 标志禁用。您也需要检查这一点,因为无法以编程方式覆盖此设置。

      【讨论】:

      • 我尝试以控制台 sn-p 工作的同一用户身份运行应用程序池。没有不同。 LoadUserProfile 为真。我还在 web.config 中添加了 。没有不同。还有什么建议吗?
      • 您是否检查过运行您网站的机器上的 web.config 或 machine.config 中没有 disableAllCaching="true"
      • 另外,您可能还想使用像Fiddler 这样的网络调试代理来检查您的网站是否实际执行了 20 个请求,并且它们的响应代码是 200 而不是 404。
      • disableAllCaching 不在 machine.config 或 web.config 中
      • 请求确实返回 200 和缓存标头
      【解决方案3】:

      作为重新配置服务器的替代方法,您可以自己缓存结果 - 可以根据您的需要将其存储在会话中。

      话虽如此,您已经将异步调用变成了阻塞调用 - 您确实应该使用回调(或承诺)。

      【讨论】:

      • 并没有真正回答这个问题,这个控制器的目的是阻止测试缓存是否有效。使用 async/await 时无需回调
      猜你喜欢
      • 1970-01-01
      • 2016-06-18
      • 2013-11-26
      • 1970-01-01
      • 2016-05-25
      • 1970-01-01
      • 1970-01-01
      • 2017-03-27
      • 1970-01-01
      相关资源
      最近更新 更多