WinInet如何确定缓存的内容和时间?

时间:2013-11-28 18:16:43

标签: .net http asp.net-web-api wininet http-caching

我正在尝试在.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 个答案:

答案 0 :(得分:4)

我使用RequestCacheLevel.Default,否则我发现Wininet很乐意提供陈旧的回复。

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

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

说完所有这些后,请检查您对不同标题的回复。在许多情况下,Vary标头会阻止使用Wininet,因为它不能正确支持变换标头。


使用此控制器,

  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");

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