• 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);
    }

    我们只需要努力,然后剩下的交给时间。
  • 相关阅读:
    彻底理解多态
    变量可以存储在堆中,栈中,方法区中。哪里都可以啊。对象只能存储在堆中
    json序列化后的是字符串,不是二进制。是字符串!!!确定不是二进制!!!
    线程流程理解
    增加一个类的功能可以采用继承或者代理模式或者装饰者模式
    Java 代理模式和装饰者模式的区别
    异常不管咋样,只要抛出了,不管是方法级别抛出,还是类级别抛出。终究有一个地方要对异常进行处理
    汉高澳大利亚sinox为什么不能下载源代码,因为sinox执行unix/linux/windows规划
    使用Visual Studio将Objective-C编译C++
    百度编辑器ueditor简单易用
  • 原文地址:https://www.cnblogs.com/lgj8/p/14955108.html
Copyright © 2020-2023  润新知