Chrome或Firefox浏览器对静态资源文件的缓存时长是多久!

先放上结论吧,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);
}
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游北亮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值