WinInet如何确定何时以及如何缓存?

8

我正在尝试在我的.NET客户端和服务器之间使用缓存。在WinInet决定缓存结果之前,我看到了一些看似随机的端点命中次数。

.NET客户端使用HttpWebRequest进行请求:

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uiTextBoxUrl.Text);
var policy = new RequestCachePolicy(RequestCacheLevel.CacheIfAvailable);
webRequest.CachePolicy = policy;
WebResponse webResponse = webRequest.GetResponse();

服务器使用ASP.net Web API实现,设置这些CacheControl头:

response.Headers.CacheControl = new CacheControlHeaderValue
        {
            MaxAge =3600,
            MustRevalidate = true,
            Public = true,
            Private = true
        };

使用具有发送请求到端点的按钮的测试工具,即使使用了“CacheIfAvailable”,我仍然可以看到响应未立即缓存。通过检查服务器上的调试输出,我发现需要似乎随机数量的点击(或更可能是命中计数/经过时间启发式),才能最终缓存请求。如果我快速点击测试按钮,它将在约10次点击后开始缓存。如果我每1或2秒钟点击一次按钮,我已经数过25次点击,然后缓存才会启动。

这是我从Fiddler看到的响应:

HTTP/200 responses are cacheable by default, unless Expires, Pragma, or Cache-Control headers are present and forbid caching.
HTTP/1.1 Cache-Control Header is present: public, must-revalidate, max-age=3600, private
    private: This response MUST NOT be cached by a shared cache.
    public: This response MAY be cached by any cache.
    max-age: This resource will expire in 1 hours. [3600 sec]
    must-revalidate: After expiration, the server MUST be contacted to verify the freshness of this resource.

HTTP/1.1 ETAG Header is present: "3488770a-8659-4fc0-b579-dcda9200a1c7"

我读到HttpWebRequest使用WinInet进行缓存,因此我很好奇WinInet如何确定需要缓存的内容,更具体地说,为什么它在第一次请求时不进行缓存?

1个回答

4

我使用RequestCacheLevel.Default,否则我发现Wininet会乐意提供过期的响应。

我也不使用must-revalidate,因为我假设这是默认行为,一旦缓存的响应过期了。

我相信,如果您始终在请求中包含LastModifed或Etag,则默认情况下,直到本地副本过期(因为您设置了Private和MaxAge),您将获得本地副本,一旦它过期,您可能会收到304返回,此时它将使用本地副本。

说了这么多,请检查您的响应是否有vary头。在许多情况下,vary头将阻止Wininet的使用,因为其不正确支持vary头。


使用此控制器,

  public class PrivateCachingController : ApiController
    {
        public HttpResponseMessage Get()
        {
            var response = new HttpResponseMessage()
            {
                Content = new StringContent("This is cached content")
            };
            response.Headers.CacheControl = new CacheControlHeaderValue() {MaxAge = new TimeSpan(0,0,0,60)};
            return response;
        }
    }

以及这段客户端代码,

var clientHandler = new WebRequestHandler();
clientHandler.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
var client = new HttpClient(clientHandler) { BaseAddress = _BaseAddress };

var response = await client.GetAsync("/PrivateCaching");
var response2 = await client.GetAsync("/PrivateCaching");

当它执行时,网络上只会发出一个请求。

谢谢@Darrell。我也尝试了“默认”缓存级别,但结果相同。我没有得到“Vary”头信息。现在我非常好奇为什么第一次不会缓存... - Steve Dunn
@SteveDunn Fiddler中的“缓存”选项卡对于未被缓存的响应有何说明? - Darrel Miller
1
@SteveDunn 我添加了示例代码,我已经运行它并且它缓存了第一个响应。第二个请求不会通过网络传输。 - Darrel Miller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接