zoukankan      html  css  js  c++  java
  • Chrome或Firefox浏览器缓存时间问题

    1、浏览器默认缓存时间

      firefox 的缓存时间时长

      (访问时间 - 最后修改时间) ÷  10

      例子:

      假设 7点0分 访问的 5点0分修改的 index.html ,

      那么缓存时间为

      2*60*60 ÷ 10 = 720 秒

      页面缓存时间为 720 秒

    2、设置页面禁止缓存

    1.  
      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
    2.  
      <meta http-equiv="Pragma" content="no-cache" />
    3.  
      <meta http-equiv="Expires" content="0" />

      

      no-cache : 协商缓存

      no-store : 不缓存

      must-revalidate : 过期强制请求服务器

    先放上结论吧,Chrome和Firefox对js、css之类的文件,在内存中的缓存时长,是:
    (访问时间 - 该文件的最后修改时间) ÷ 10

    假设文件 a.js 最后编辑时间是 2018年12月1号 10点0分0秒;
    Chrome的第一次访问时间是 2018年12月1号 12点0分0秒;
    第一次访问与文件编辑时间相差2小时,即7200秒,那么缓存时长就是720秒
    即结论如下:
    1、在 2018年12月1号 12点0分1秒到 12点11分59秒,这12分钟内,浏览器不会发起http请求;
    2、在 2018年12月1号 12点12分0秒,会发起带 If-Modified-Since 的http请求
    3、如果希望浏览器每次都发起http请求,请在WebServer返回Header Cache-Control: no-cache

    问题的由来:
    我提供了一个多语言的js资源包服务,昨天有QA反馈,后台修改了内容,前台没变化!!
    PC上还好办,可以按Ctrl + F5,强制刷新,手机上就不好办了,只能等着缓存过期。
    而且我们也不可能主动通知用户去强制刷新吧!

    问题解决很简单,在IIS的站点=》HTTP响应标头里,添加一个Header:Cache-Control,值为no-cache,
    问题解决。
    注意:加了这个标头后,浏览器在请求这个站点的js/css/图片资源时,每次都会重新发起HTTP连接请求,虽然请求的Header里会带上 If-Modified-Since,但是HTTP连接本身也是很耗资源的,所以要根据场景来选择性添加,
    比如不添加标头,而是通过js加版本号来避免缓存。

    虽然缓存问题解决了,但是如果没加标头,Chrome会在内存缓存多久啊?这个问题我搜索了一下,没有找到Chrome的资料,但是有文章说Firefox是按顶部的结论实现的,参考RFC协议关于缓存过期的部分:
    https://tools.ietf.org/html/rfc2616#section-13.2.4

    为了验证,写了一个html定时刷新自己,然后扔在IIS站点下,然后用Chrome的F12->Network抓包:

    <!DOCTYPE html>
    <html>
    <head>
    <script type="text/javascript" src="jq_125bece.js"></script>
    <script type="text/javascript" src="errnew.js"></script>
    <link rel="stylesheet" href="a.css"/>
    <script type="text/javascript">
    $(document).ready(function() {
    setTimeout(function(){
    location.href = 'a.html?' + Date.now();
    }, 10000);
    });
    </script>
    </head>
    <body>
    </body>
    </html>

    验证的结果,Chrome也是按这个机制作为本地缓存过期策略。

    文章最后,贴一段C#版本的判断304响应的代码,用于客户端更新本地资源:

    static void Main(string[] args)
    {
    var url = "https://beinet.cn/language.js";
    var localFile = @"d:language.js";

    var ret = UpdateResource(url, localFile);
    Console.WriteLine("是否有更新" + ret);

    ret = UpdateResource(url, localFile);
    Console.WriteLine("是否有更新" + ret);
    Console.Read();
    }


    /// <summary>
    /// 更新本地资源文件,并返回是否进行了更新
    /// </summary>
    /// <param name="url">远程资源文件地址</param>
    /// <param name="localFile">本地缓存资源地址</param>
    /// <returns></returns>
    static bool UpdateResource(string url, string localFile)
    {
    const string responseHeader = "Last-Modified";
    var timeFile = localFile + responseHeader;
    string lastModified = null;
    if (File.Exists(timeFile))
    {
    lastModified = File.ReadAllText(timeFile);
    }

    var request = (HttpWebRequest)WebRequest.Create(url);
    request.Headers.Add("Accept-Encoding", "gzip, deflate");
    request.Timeout = 5000; // 默认5秒超时
    request.AllowAutoRedirect = true;
    if (!string.IsNullOrEmpty(lastModified))
    {
    request.IfModifiedSince = DateTime.Parse(lastModified); // 设置Header if-modified-since
    }
    string json;
    HttpWebResponse response;
    try
    {
    response = (HttpWebResponse) request.GetResponse();
    }
    catch (WebException exp)
    {
    if(exp.Response != null && ((HttpWebResponse)exp.Response).StatusCode == HttpStatusCode.NotModified)
    return false;
    throw;
    }
    using (response)
    {
    lastModified = response.Headers[responseHeader];
    json = GetResponseString(response, Encoding.UTF8);
    }
    // todo: 这里要考虑判断是否json格式
    SaveToFile(localFile, json);
    SaveToFile(timeFile, lastModified);
    return true;
    }

    /// <summary>
    /// 从HttpResposne中获取响应字符串
    /// </summary>
    /// <param name="response"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    static string GetResponseString(HttpWebResponse response, Encoding encoding)
    {
    using (Stream stream = response.GetResponseStream())
    {
    if (stream == null)
    {
    return "GetResponseStream is null";
    }
    string str;
    string contentEncoding = response.ContentEncoding.ToLower();
    if (contentEncoding.Contains("gzip"))
    {
    using (Stream stream2 = new GZipStream(stream, CompressionMode.Decompress))
    {
    str = GetFromStream(stream2, encoding);
    }
    }
    else if (contentEncoding.Contains("deflate"))
    {
    using (Stream stream2 = new DeflateStream(stream, CompressionMode.Decompress))
    {
    str = GetFromStream(stream2, encoding);
    }
    }
    else
    {
    str = GetFromStream(stream, encoding);
    }
    return str;
    }
    }

    static string GetFromStream(Stream stream, Encoding encoding)
    {
    using (StreamReader reader = new StreamReader(stream, encoding))
    {
    return reader.ReadToEnd();
    }
    }

    static void SaveToFile(string targetFile, string content)
    {
    var now = DateTime.Now.ToString("yyyyMMddHHmmssfffffff");
    // 写入临时文件,再进行移动
    var tmpFile = targetFile + now;
    File.WriteAllText(tmpFile, content);

    if (File.Exists(targetFile))
    {
    var bakFile = targetFile + "bak" + now; // 备份文件
    File.Move(targetFile, bakFile);
    }
    File.Move(tmpFile, targetFile);
    }

    我们只需要努力,然后剩下的交给时间。
  • 相关阅读:
    解决docker-compose: command not found
    idea 包存在提示不存在
    使用haproxy负载均衡
    docker使用阿里云仓库上传与下拉images
    docker使用官方仓库上传与下拉images
    WeaveScope-容器监控
    matlab打开
    硬盘测试
    matlab quiver()画箭头的函数
    SDK 和 API 的区别是什么?
  • 原文地址:https://www.cnblogs.com/lgj8/p/14955108.html
Copyright © 2011-2022 走看看