美文网首页知识点程序猿极乐科技
localStorage的黑科技-js和css缓存机制

localStorage的黑科技-js和css缓存机制

作者: 我_是leon | 来源:发表于2017-01-18 20:30 被阅读5163次

    一、发现黑科技的起因

    今天在微信公众号看到一篇技术博文,想用印象笔记收藏,所以发送了文章链接到pc上。然后习惯性地打开控制台,看看源码,想了解下最近微信用了什么新技术。
     呵呵,以下勾起了我侦探的欲望。页面加载后的异常点就是只加载了一个js,如下图所示:

    我很诧异,为什么已经开启了Disable cache,js只加载了一个,而且体积这么小。接着,我按住Ctrl+O进行资源文件查找,发现我被“忽悠”了。其实根本就不止一个js文件。

    脑袋里灵光一闪,不会是用localStorage做了缓存吧?!赶紧看了下localStronge,还真是。。。。

    心里一阵澎湃,这不是我之前就想实现的加载性能优化的想法吗!乖乖,我孤陋寡闻了,已经有前端团队实现了代码。

    二、谈谈文件加载方面的优化思路

    通常,前端的资源文件加载优化,就是在文件不修改迭代的情况下,尽可能多地利用缓存,避免多次下载同样的文件。
     一般的做法就是尽量延长资源的有效期,也就是设置 Cache-Control里的max-age,使页面资源请求的返回码为304,让浏览器直接使用本地缓存。
     虽然pc端的协商缓存(304)很快,但手机端因为网络原因,协商缓存的效果就没pc端那么好了。而且,手机会经常清除本地缓存,所以文件缓存的时间也不会很长。
     这个时候,localStorage就派上用场了。
     localStorage相比cookie,可以缓存大体积的数据,而且是永久有效。所以,如果把js资源和css资源存储在localStorage中,则可以省去发送http请求所消耗的时间,大大提高用户的浏览体验。

    三、用localStorage做资源缓存需要解决的问题

    3.1 版本更新机制

    只要一个项目还在迭代开发,就难以避免需要更新资源文件。
     普通的资源请求,可以根据
     文件名+md5 http://res.wx.qq.com/mmbizwap/zh_CN/htmledition/js/biz_wap/moon32ebc4.js
     或者
     在资源链接后面加上特定的后缀http://1.ss.faisys.com/js/comm/fai.min.js?v=201612051739
     做标识来判断是否需要更新资源。
     如果用localStorage做,则需要一套新的缓存更新机制。

    3.2 搭建更新代码的脚手架

    使用localStorage缓存,则需要一个新的脚手架来管理资源文件的读取和写入。

    3.3 后台输出一份资源配置信息

    因为需要前端做资源更新,所以后台要输出一份依据给前端做判断用,也就是需要一份资源配置信息。前端根据配置信息,进行匹配和比较,最终决定 使用localStorage缓存,还是重新发起请求,下载最新的资源文件。

    3.4 存在XSS安全隐患

    localStorage中的信息,客户端是可以任意修改的。如果哪个黑客想练手一下,可以任意注入js代码。那么,在页面刷新的时候,注入的代码也将会被执行。

    四、微信的做法解析

    4.1 版本标识

    __MOON__a/a_report.js为例,版本信息用key __MOON__a/a_report.js_ver存储,存储的value为//res.wx.qq.com/mmbizwap/zh_CN/htmledition/js/a/a_report32e586.js
     如果按普通加载方式,直接将该value取出来,设置到script节点的src属性,即可完成加载。
     微信判断该版本是否最新,就是用该value值与后台输出的配置信息进行比较,最后得出是否更新的结果。
     如果value值与配置信息一致,则使用缓存。否则,重新发起请求加载。

    4.2 脚手架

    可以看出,微信使用的是自己开发的脚手架moon.js,在这个网页中的实际文件名是moon32ebc4.js
     因为是混淆过变量名的文件,所以要看出具体代码的走向,有点费劲,这里就不做分析了。

    4.3 资源配置信息

    因为脚手架moon.js需要资源配置信息才能正常工作,所以配置信息一定会在moon.js之前输出。
     依次查看moon.js之前的script标签,发现了window.moon_map这个json对象。

    利用控制台输出该变量查看信息如下:

    看到这里,可以明确一个点:这就是更新机制所必备的资源配置信息表了。
     而且,可以看出,该配置信息json对象的key,就对应localStorage中的key。同理,value值也是一一对应。

    4.4 XSS攻击

    此处是为了验证微信的缓存机制是否存在XSS攻击,看到这里的童鞋可千万不要去做坏事。
     我在一个js缓存代码中,插入alert("hehe");,看页面刷新的时候,是否会出现该弹窗,来验证是否存在攻击漏洞。

    刷新页面后,结果如下图:

    可以看出,微信也没有解决这类问题。所以,这种缓存机制,还是有先天不足的。

    4.5 测试微信的更新机制

    修改localStorage中 key __MOON__a/a_report.js_ver对应的value值,让微信的脚手架moon.js更新__MOON__a/a_report.js,刷掉我刚才主动插入的代码。
     这里,我修改文件名为***587.js(原来的文件名为***586.js)。接着F5刷新页面。
     结果为:report.js代码更新了,版本号也恢复回 ***586.js

    五、结论

    localStorage缓存有其用武之地,但不是万能的。需要注意以上提及的坑。
     可以应用的场景我归纳为以下几点:

    1. 非首屏渲染需要的css文件,可以做LS缓存。

    首屏渲染需要的css,需要按常规方式输出,因为SEO需要,不然爬虫爬取页面的时候,页面效果会很不好。而非首屏的css,则可以用LS缓存,减少资源下载时间。

    2. 展示类、动画类等非业务主要逻辑的代码,可以做LS缓存。

    这样,可以一定程度上避免业务层的安全漏洞。当然,前端再怎么做防护都是一层薄纸。重要的,还是后台接口要做好安全保护。

    3. 移动端可以做LS缓存。PC端做LS缓存,起到的优化作用不大。

    六、番外

    有兴趣的童鞋,还可以看看知乎上大神们的讨论,静态资源(JS/CSS)存储在localStorage有什么缺点?为什么没有被广泛应用? - 互联网 - 知乎
     另外,腾讯网的前端,在gitHub上有分享其MT 模块管理框架,可以看看具体的实现逻辑。
     最后,上一个栗子 —— 线上实例demo:webapp模块化开发体系


    喜欢我文章的朋友,扫描以下二维码,关注我的个人技术博客,我的技术文章会第一时间在博客上更新

    点击链接wall的个人博客

    wall的个人博客

    相关文章

      网友评论

      • RockerLau:感谢您的分享,想请教下,文中第二部分提到的304向后端查询(方案A),文中第三部分第三点向后端获取配置信心(方案B)。方案B的配置是无疑是实时的,所以方案B应该是后端直出这些配置吧?不然每次都去发送请求询问就看不出优势在哪里了。
        209bd3bc6844:@wall_wxk 后端直出的意思是,查询配置是一个接口,每次前端刷新页面之类的都和后端请求,然后对比资源。后端一旦更新了资源就要更新接口。是这样理解吗
        我_是leon:@Beyond_Xiang 对的,后端直出配置信息
      • 506b572b6aa3:不是早就有这方面的实践了嘛
      • 让周飞:在js缓存中加alert只能影响你自己的页面吧?
        隐木:这个确实不是XSS,增加中间人代理也可以随便改前端资源的
        夏日小可:@wall_wxk 个人觉得你说的xss这个不对,看过之前Twitter的localStorage的xss攻击案例,他是在存入的没有没有对<script>标签进行过滤,而腾讯这个只能影响到你自己的js http://blog.csdn.net/yangdeli888/article/details/7735260
        我_是leon:@让周飞 你可以搜索下xss攻击,可以做很多事。比如伪造请求到服务器,那就不只影响自己的页面了
      • 接灰的电子产品:不错,今天正好我也翻译了一篇,里面有一个优化点就是通过localStorage
        我_是leon::smiley: 好巧

      本文标题:localStorage的黑科技-js和css缓存机制

      本文链接:https://www.haomeiwen.com/subject/azdbbttx.html