静态资源缓存控制编译工具

前不久在 知乎 上回答了一个问题:大公司里怎样开发和部署前端代码?。其中讲到了大公司在前端静态资源部署上的一些要求: 配置超长时间的本地缓存 —— 节省带宽,提高性能 采用内容摘要作为缓存更新依据 —— 精确的缓存控制 静态资源CDN部署 —— 优化网络请求 更资源发布路径实现非覆盖式发布 —— 平滑升级 其中比较复杂的部分就是 以文件的摘要信息为依据,控制缓存更新与非覆盖式发布 这个细节。因此基于 fis 包装了一个简单的命令行工具,并设立此项目,用于演示这部分功能。 这个工具基于 fis 的小工具是完全可以用作工程中的,有任何问题可以在 这里 留言。 请跟着下面的步骤来使用这个命令行小工具: 第一步:安装工具 这个命令行小工具依赖 nodejs 环境,因此,请先确保本地安装了它。 使用 nodejs 随带的 npm 包管理工具进行安装:

第二步:创建项目 在 命令行 下clone本仓库,或者自己创建一个新的项目,并进入:

在项目根目录下创建一个空的 fis-conf.js 文件,这是工具配置,什么都不用写,空着就行。 然后开始在项目目录下,随意创建或添加 页面、脚本、样式、图片、字体、音频、视频等等前端资源文件,正常写前端代码吧! 第三步:发布代码 在项目根目录下执行:

然后去到 ../output 目录下去查看一下产出结果吧,所有静态资源都以md5摘要形式发布了出来,所有资源链接,我说 所有链接,包括html中的图片、样式、脚本以及js中的资源地址、css中的资源地址全部都加上了md5戳。 上述命令中,--md5 就是表示要给所有资源定位标记加上摘要信息的意思,不加这个参数就没有摘要信息处理。--dest ../output 表示把代码发布到当前目录上一级的output目录中。整个这条命令还可以简写成:

或者进一步连写成:

在本地服务器中浏览发布代码 你本地安装了诸如 Apache、Nginx、Lighttpd、IIS等服务器么?如果安装了,假设你的服务器 根目录 在 d:\wwwroot,你可以利用rsd工具的release命令,把代码发布过去,比如:

这样就把代码发布到了本地服务器根目录下,然后就可以在浏览器中查看效果了! 如果你本地没有安装任何服务器,你可以使用rsd内置的调试服务器,执行命令:

接下来我们同样要把代码发布到这个内置服务器中,release命令如果省略 --dest <path>参数,就表示把代码发布到内置服务器的根目录下:

在浏览器中访问: http://localhost:8080 即可   一些小技巧 rsd集成了对很多前端编程语言的支持,包括: 类CSS语言:less, sass, scss, stylus 类JS语言:coffee-script 类HTML语言:markdown, jade 前端模板:handlebars-v1.3.0, EJS 内置了压缩器,在release的时候追加 -o 或者 --optimize 参数即可开启,压缩器包括: clean-css: 压缩所有类CSS语言代码 uglify-js: 压缩所有类JS语言代码 html-minifier: 压缩所有类HTML语言代码 还可以给资源加CDN域名,在release的时候追加 -D 或者 --domains 参数即可,域名配置写在fis-conf.js里:

所有常规代码中的资源定位接口都会经过工具处理,包括: 类CSS文件中: 背景图url font-face字体url ie特有的滤镜属性中的src 类JS文件中: 提供了一个叫 __uri('path/to/file') 的编译函数用于定位资源 类HTML文件中: link标签的href属性 script, img, video, audio, object 等标签的src属性 script标签中js代码里的资源定位标记 style标签中css代码里的资源定位标记 所有资源文件可以任意相互引用,工具会处理资源定位标记,使之服从知乎回答中提到的优化策略。 还提供了资源内嵌的编译接口,用于把一个资源的内容以文本、字符串或者base64的形式嵌入到 任意 一个文本文件中。 为了不用每次保存代码就执行一下release命令,工具中提供了文件监听和浏览器自动刷新功能,只要在release的时候在追加上 -w 和 -L 两个参数即可(注意L的大小写),比如:

关于这个小工具 它的原码在 这里。是的,就这么一点点代码,花了大概半小时写完的,因为一切都在 fis 中集成好了,我只是追加几个语言编译插件而已。   from:https://github.com/fouber/static-resource-digest-project

龙生   19 Oct 2018
View Details

变态的静态资源缓存与更新

这是一个非常有趣的 非主流前端领域,这个领域要探索的是如何用工程手段解决前端开发和部署优化的综合问题,入行到现在一直在学习和实践中。 在我的印象中,facebook是这个领域的鼻祖,有兴趣、有梯子的同学可以去看看facebook的页面源代码,体会一下什么叫工程化。 接下来,我想从原理展开讲述,多图,较长,希望能有耐心看完。 让我们返璞归真,从原始的前端开发讲起。上图是一个“可爱”的index.html页面和它的样式文件a.css,用文本编辑器写代码,无需编译,本地预览,确认OK,丢到服务器,等待用户访问。前端就是这么简单,好好玩啊,门槛好低啊,分分钟学会有木有! 然后我们访问页面,看到效果,再查看一下网络请求,200!不错,太™完美了!那么,研发完成。。。。了么? 等等,这还没完呢!对于大公司来说,那些变态的访问量和性能指标,将会让前端一点也不“好玩”。 看看那个a.css的请求吧,如果每次用户访问页面都要加载,是不是很影响性能,很浪费带宽啊,我们希望最好这样: 利用304,让浏览器使用本地缓存。但,这样也就够了吗?不成!304叫协商缓存,这玩意还是要和服务器通信一次,我们的优化级别是变态级,所以必须彻底灭掉这个请求,变成这样: 强制浏览器使用本地缓存(cache-control/expires),不要和服务器通信。好了,请求方面的优化已经达到变态级别,那问题来了:你都不让浏览器发资源请求了,这缓存咋更新? 很好,相信有人想到了办法:通过更新页面中引用的资源路径,让浏览器主动放弃缓存,加载新资源。好像这样: 下次上线,把链接地址改成新的版本,就更新资源了不是。OK,问题解决了么?!当然没有!大公司的变态又来了,思考这种情况: 页面引用了3个css,而某次上线只改了其中的a.css,如果所有链接都更新版本,就会导致b.css,c.css的缓存也失效,那岂不是又有浪费了?! 重新开启变态模式,我们不难发现,要解决这种问题,必须让url的修改与文件内容关联,也就是说,只有文件内容变化,才会导致相应url的变更,从而实现文件级别的精确缓存控制。 什么东西与文件内容相关呢?我们会很自然的联想到利用 数据摘要要算法 对文件求摘要信息,摘要信息与文件内容一一对应,就有了一种可以精确到单个文件粒度的缓存控制依据了。好了,我们把url改成带摘要信息的: 这回再有文件修改,就只更新那个文件对应的url了,想到这里貌似很完美了。你觉得这就够了么?大公司告诉你:图样图森破! 唉~~~~,让我喘口气 现代互联网企业,为了进一步提升网站性能,会把静态资源和动态网页分集群部署,静态资源会被部署到CDN节点上,网页中引用的资源也会变成对应的部署路径: 好了,当我要更新静态资源的时候,同时也会更新html中的引用吧,就好像这样: 这次发布,同时改了页面结构和样式,也更新了静态资源对应的url地址,现在要发布代码上线,亲爱的前端研发同学,你来告诉我,咱们是先上线页面,还是先上线静态资源? 1.先部署页面,再部署资源:在二者部署的时间间隔内,如果有用户访问页面,就会在新的页面结构中加载旧的资源,并且把这个旧版本的资源当做新版本缓存起来,其结果就是:用户访问到了一个样式错乱的页面,除非手动刷新,否则在资源缓存过期之前,页面会一直执行错误。 2.先部署资源,再部署页面:在部署时间间隔之内,有旧版本资源本地缓存的用户访问网站,由于请求的页面是旧版本的,资源引用没有改变,浏览器将直接使用本地缓存,这种情况下页面展现正常;但没有本地缓存或者缓存过期的用户访问网站,就会出现旧版本页面加载新版本资源的情况,导致页面执行错误,但当页面完成部署,这部分用户再次访问页面又会恢复正常了。 好的,上面一坨分析想说的就是:先部署谁都不成!都会导致部署过程中发生页面错乱的问题。所以,访问量不大的项目,可以让研发同学苦逼一把,等到半夜偷偷上线,先上静态资源,再部署页面,看起来问题少一些。 但是,大公司超变态,没有这样的“绝对低峰期”,只有“相对低峰期”。So,为了稳定的服务,还得继续追求极致啊! 这个奇葩问题,起源于资源的覆盖式发布,用 待发布资源覆盖 已发布资源,就有这种问题。解决它也好办,就是实现非覆盖式发布。 看上图,用文件的摘要信息来对资源文件进行重命名,把摘要信息放到资源文件发布路径中,这样,内容有修改的资源就变成了一个新的文件发布到线上,不会覆盖已有的资源文件。上线过程中,先全量部署静态资源,再灰度部署页面,整个问题就比较完美的解决了。 所以,大公司的静态资源优化方案,基本上要实现这么几个东西: 1.配置超长时间的本地缓存 —— 节省带宽,提高性能 2.采用内容摘要作为缓存更新依据 —— 精确的缓存控制 3.静态资源CDN部署 —— 优化网络请求 4.更资源发布路径实现非覆盖式发布 —— 平滑升级 全套做下来,就是相对比较完整的静态资源缓存控制方案了,而且,还要注意的是,静态资源的缓存控制要求在 前端所有静态资源加载的位置都要做这样的处理 。是的,所有!什么js、css自不必说,还要包括js、css文件中引用的资源路径,由于涉及到摘要信息,引用资源的摘要信息也会引起引用文件本身的内容改变,从而形成级联的摘要变化,大概示意图就是: 好了,目前我们快速的学习了一下前端工程中关于静态资源缓存要面临的优化和部署问题,新的问题又来了:这™让工程师怎么写码啊!!! 要解释优化与工程的结合处理思路,又会扯出一堆有关模块化开发、资源加载、请求合并、前端框架等等的工程问题,以上只是开了个头,解决方案才是精髓,但要说的太多太多,有空再慢慢展开吧。 总之,前端性能优化绝逼是一个工程问题! 以上不是我YY的,可以观察 百度 或者 facebook 的页面以及静态资源源代码,查看它们的资源引用路径处理,以及网络请中静态资源的缓存控制部分。再次赞叹facebook的前端工程建设水平,跪舔了。 建议前端工程师多多关注前端工程领域,也许有人会觉得自己的产品很小,不用这么变态,但很有可能说不定某天你就需要做出这样的改变了。而且,如果我们能把事情做得更极致,为什么不去做呢? 另外,也不要觉得这些是运维或者后端工程师要解决的问题。如果由其他角色来解决,大家总是把自己不关心的问题丢给别人,那么前端工程师的开发过程将受到极大的限制,这种情况甚至在某些大公司都不少见! 妈妈,我再也不玩前端了。。。。5555   业界实践 Assets Pipeline Rails中的Assets Pipeline完成了以上所说的优化细节,对整个静态资源的管理上的设计思考也是如此,了解rails的人也可以把此答案当做是对rails中assets pipeline设计原理的分析。 rails通过把静态资源变成erb模板文件,然后加入<%= asset_path 'image.png' %>,上线前预编译完成处理,fis的实现思路跟这个几乎完全一样,但我们当初确实不知道有rails的这套方案存在。 相关资料: 英文版:http://guides.rubyonrails.org/asset_pipeline.html 中文版:http://guides.ruby-china.org/asset_pipeline.html FIS的解决方案 用 F.I.S 包装了一个小工具,完整实现整个回答所说的最佳部署方案,并提供了源码对照,可以感受一下项目源码和部署代码的对照。 源码项目:https://github.com/fouber/static-resource-digest-project 部署项目:https://github.com/fouber/static-resource-digest-project-release 部署项目可以理解为线上发布后的结果,可以在部署项目里查看所有资源引用的md5化处理。 这个示例也可以用于和assets pipeline做比较。fis没有assets的目录规范约束,而且可以以独立工具的方式组合各种前端开发语言(coffee、less、sass/scss、stylus、markdown、jade、ejs、handlebars等等你能想到的),并与其他后端开发语言结合。 assets pipeline的设计思想值得独立成工具用于前端工程,fis就当做这样的一个选择吧。   from:https://www.cnblogs.com/minigrasshopper/p/7694053.html

龙生   17 Oct 2018
View Details

前端工程精粹(一):静态资源版本更新与缓存

每个参与过开发企业级web应用的前端工程师或许都曾思考过前端性能优化方面的问题。我们有雅虎14条性能优化原则,还有两本很经典的性能优化指导书:《高性能网站建设指南》、《高性能网站建设进阶指南》。经验丰富的工程师对于前端性能优化方法耳濡目染,基本都能一一列举出来。这些性能优化原则大概是在7年前提出的,对于web性能优化至今都有非常重要的指导意义。 然而,对于构建大型web应用的团队来说,要坚持贯彻这些优化原则并不是一件十分容易的事。因为优化原则中很多要求是与工程管理相违背的,比如“把css放在头部”和“把js放在尾部”这两条原则,我们不能让团队的工程师在写样式和脚本引用的时候都去修改一个相同的页面文件。这样做会严重影响团队成员间并行开发的效率,尤其是在团队有版本管理的情况下,每天要花大量的时间进行代码修改合并,这项成本是难以接受的。因此在前端工程界,总会看到周期性的性能优化工作,辛勤的前端工程师们每到月圆之夜就会倾巢出动根据优化原则做一次性能优化。 本文从一个全新的视角来思考web性能优化与前端工程之间的关系,通过解读百度前端集成解决方案小组(F.I.S)在打造高性能前端架构并统一百度40多条前端产品线的过程中所经历的技术尝试,揭示前端性能优化在前端架构及开发工具设计层面的实现思路。 性能优化原则及分类 笔者先假设本文的读者是有前端开发经验的工程师,并对企业级web应用开发及性能优化有一定的思考,因此我不会重复介绍雅虎14条性能优化原则。如果您没有这些前续知识,请移步这里来学习。 首先,我们把雅虎14条优化原则,《高性能网站建设指南》以及《高性能网站建设进阶指南》中提到的优化点做一次梳理,按照优化方向分类,可以得到这样一张表格: 优化方向 优化手段 请求数量 合并脚本和样式表,CSS Sprites,拆分初始化负载,划分主域 请求带宽 开启GZip,精简JavaScript,移除重复脚本,图像优化 缓存利用 使用CDN,使用外部JavaScript和CSS,添加Expires头,减少DNS查找,配置ETag,使AjaX可缓存 页面结构 将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出 代码校验 避免CSS表达式,避免重定向 表格1 性能优化原则分类 目前大多数前端团队可以利用yui compressor或者google closure compiler等压缩工具很容易做到“精简Javascript”这条原则;同样的,也可以使用图片压缩工具对图像进行压缩,实现“图像优化”原则。这两条原则是对单个资源的处理,因此不会引起任何工程方面的问题。很多团队也通过引入代码校验流程来确保实现“避免css表达式”和“避免重定向”原则。目前绝大多数互联网公司也已经开启了服务端的Gzip压缩,并使用CDN实现静态资源的缓存和快速访问;一些技术实力雄厚的前端团队甚至研发出了自动CSS Sprites工具,解决了CSS Sprites在工程维护方面的难题。使用“查找-替换”思路,我们似乎也可以很好的实现“划分主域”原则。 我们把以上这些已经成熟应用到实际生产中的优化手段去除掉,留下那些还没有很好实现的优化原则。再来回顾一下之前的性能优化分类: 优化方向 优化手段 请求数量 合并脚本和样式表,拆分初始化负载 请求带宽 移除重复脚本 缓存利用 添加Expires头,配置ETag,使Ajax可缓存 页面结构 将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出 表格2 较难实现的优化原则 现在有很多顶尖的前端团队可以将上述还剩下的优化原则也都一一解决,但业界大多数团队都还没能很好的解决这些问题。因此,本文将就这些原则的解决方案做进一步的分析与讲解,从而为那些还没有进入前端工业化开发的团队提供一些基础技术建设意见,也借此机会与业界顶尖的前端团队在工业化工程化方向上交流一下彼此的心得。 静态资源版本更新与缓存 如表格2所示,“缓存利用”分类中保留了“添加Expires头”和“配置ETag”两项。或许有些人会质疑,明明这两项只要配置了服务器的相关选项就可以实现,为什么说它们难以解决呢?确实,开启这两项很容易,但开启了缓存后,我们的项目就开始面临另一个挑战:如何更新这些缓存。 相信大多数团队也找到了类似的答案,它和《高性能网站建设指南》关于“添加Expires头”所说的原则一样——修订文件名。即: 最有效的解决方案是修改其所有链接,这样,全新的请求将从原始服务器下载最新的内容。 思路没错,但要怎么改变链接呢?变成什么样的链接才能有效更新缓存,又能最大限度避免那些没有修改过的文件缓存不失效呢? 先来看看现在一般前端团队的做法: 或者 大家会采用添加query的形式修改链接。这样做是比较直观的解决方案,但在访问量较大的网站,这么做可能将面临一些新的问题。 通常一个大型的web应用几乎每天都会有迭代和更新,发布新版本也就是发布新的静态资源和页面的过程。以上述代码为例,假设现在线上运行着index.html文件,并且使用了线上的a.js资源。index.html的内容为: 这次我们更新了页面中的一些内容,得到一个index.html文件,并开发了新的与之匹配的a.js资源来完成页面交互,新的index.html文件的内容因此而变成了:   好了,现在要开始将两份新的文件发布到线上去。可以看到,index.html和a.js的资源实际上是要覆盖线上的同名文件的。不管怎样,在发布的过程中,index.html和a.js总有一个先后的顺序,从而中间出现一段或大或小的时间间隔。对于一个大型互联网应用来说即使在一个很小的时间间隔内,都有可能出现新用户访问。在这个时间间隔中,访问了网站的用户会发生什么情况呢? 如果先覆盖index.html,后覆盖a.js,用户在这个时间间隙访问,会得到新的index.html配合旧的a.js的情况,从而出现错误的页面。 如果先覆盖a.js,后覆盖index.html,用户在这个间隙访问,会得到旧的index.html配合新的a.js的情况,从而也出现了错误的页面。 这就是为什么大型web应用在版本上线的过程中经常会较集中的出现前端报错日志的原因,也是一些互联网公司选择加班到半夜等待访问低峰期再上线的原因之一。此外,由于静态资源文件版本更新是“覆盖式”的,而页面需要通过修改query来更新,对于使用CDN缓存的web产品来说,还可能面临CDN缓存攻击的问题。我们再来观察一下前面说的版本更新手段: 我们不难预测,a.js的下一个版本是“1.0.1”,那么就可以刻意构造一串这样的请求“a.js?v=1.0.1”、“a.js?v=1.0.2”、……让CDN将当前的资源缓存为“未来的版本”。这样当这个页面所用的资源有更新时,即使更改了链接地址,也会因为CDN的原因返回给用户旧版本的静态资源,从而造成页面错误。即便不是刻意制造的攻击,在上线间隙出现访问也可能导致区域性的CDN缓存错误。 此外,当版本有更新时,修改所有引用链接也是一件与工程管理相悖的事,至少我们需要一个可以“查找-替换”的工具来自动化的解决版本号修改的问题。 对付这个问题,目前来说最优方案就是基于文件内容的hash版本冗余机制了。也就是说,我们希望工程师源码是这么写的: 但是线上代码是这样的: 其中”_82244e91”这串字符是根据a.js的文件内容进行hash运算得到的,只有文件内容发生变化了才会有更改。由于版本序列是与文件名写在一起的,而不是同名文件覆盖,因此不会出现上述说的那些问题。同时,这么做还有其他的好处: 线上的a.js不是同名文件覆盖,而是文件名+hash的冗余,所以可以先上线静态资源,再上线html页面,不存在间隙问题; 遇到问题回滚版本的时候,无需回滚a.js,只须回滚页面即可; 由于静态资源版本号是文件内容的hash,因此所有静态资源可以开启永久强缓存,只有更新了内容的文件才会缓存失效,缓存利用率大增; 修改静态资源后会在线上产生新的文件,一个文件对应一个版本,因此不会受到构造CDN缓存形式的攻击 虽然这种方案是相比之下最完美的解决方案,但它无法通过手工的形式来维护,因为要依靠手工的形式来计算和替换hash值,并生成相应的文件。这将是一项非常繁琐且容易出错的工作,因此我们需要借助工具。我们下面来了解一下fis是如何完成这项工作的。 首先,之所以有这种工具需求,完全是由web应用运行的根本机制决定的:web应用所需的资源是以字面的形式通知浏览器下载而聚合在一起运行的。这种资源加载策略使得web应用从本质上区别于传统桌面应用的版本更新方式。为了实现资源定位的字面量替换操作,前端构建工具理论上需要识别所有资源定位的标记,其中包括: css中的@import url(path)、background:url(path)、backgournd-image:url(path)、filter中的src js中的自定义资源定位函数,在fis中我们将其规定为__uri(path)。 html中的<script src=”path”>、<link href=”path”>、<imgsrc=”path”>、已经embed、audio、video、object等具有资源加载功能的标签。 为了工程上的维护方便,我们希望工程师在源码中写的是相对路径,而工具可以将其替换为线上的绝对路径,从而避免相对路径定位错误的问题(比如js中需要定位图片路径时不能使用相对路径的情况)。 fis的资源定位设计思想 fis有一个非常棒的资源定位系统,它是根据用户自己的配置来指定资源发布后的地址,然后由fis的资源定位系统识别文件中的定位标记,计算内容hash,并根据配置替换为上线后的绝对url路径。 要想实现具备hash版本生成功能的构建工具不是“查找-替换”这么简单的。我们考虑这样一种情况: 资源引用关系 由于我们的资源版本号是通过对文件内容进行hash运算得到,如上图所示,index.html中引用的a.css文件的内容其实也包含了a.png的hash运算结果,因此我们在修改index.html中a.css的引用时,不能直接计算a.css的内容hash,而是要先计算出a.png的内容hash,替换a.css中的引用,得到了a.css的最终内容,再做hash运算,最后替换index.html中的引用。 这意味着构建工具需要具备“递归编译”的能力,这也是为什么fis团队不得不放弃gruntjs等task-based系统的根本原因。针对前端项目的构建工具必须是具备递归处理能力的。此外,由于文件之间的交叉引用等原因,fis构建工具还实现了构建缓存等机制,以提升构建速度。 在解决了基于内容hash的版本更新问题之后,我们可以将所有前端静态资源开启永久强缓存,每次版本发布都可以首先让静态资源全量上线,再进一步上线模板或者页面文件,再也不用担心各种缓存和时间间隙的问题了! 在本系列的下一部分,我们将介绍静态资源管理与模板框架的思路和用法。 作者简介:张云龙,百度公司Web前端研发部前端集成解决方案小组技术负责人,目前负责F.I.S项目,读者可以关注他的微博:http://weibo.com/fouber/。   from:http://www.infoq.com/cn/articles/front-end-engineering-and-performance-optimization-part1

龙生   15 Oct 2018
View Details

前端静态资源的缓存和更新问题解析

浏览器缓存主要有两类 缓存协商:Last-midified ,Etag 彻底缓存:cache-control,Expires 缓存协商的意思是需要去服务器端询问页面有没有修改过,没有修改过则返回304直接使用缓存内容,否则返回新内容 协商步骤: 1、服务器发送带Last-midified:GMTtime 头的http response 2、浏览器下次请求时带上if-modified-since:GMTtime http 请求头 3、服务端用本地Last-midified时间与if-modified-since比较,计算浏览器数据是否过期并发送响应 Etag的工作原理与Last-midified类似,不同点在于Etag的值是用户可自定义的 彻底缓存的意思是在缓存失效之前不再需要跟服务器交互 常用的是Expires,Expires的值是一个绝对时间,由服务器产生 这儿存在一个问题,就是服务器的时间可能给客户端的时间不一致导致缓存时间的偏差 要解决这个问题就要使用cache-control,它保存的是一个相对浏览器的时间 如果同时存在cache-control和Expires怎么办呢? 浏览器总是优先使用cache-control,如果没有cache-control才考虑Expires expire: 如果apache开启了expire模块, 当浏览器发送该资源请求的时候, apache返回资源的同时,会返回一个名为expire的http头,expire头的内容是一个时间值, 这一个值就是资源在本地的过期时间, 这个值会存在本地. 也就是说,在本地缓存阶段,在本地找到了一个对应的资源值,而且当前时间还没超过资源的过期时间, 那么就直接使用这一个资源,不会发送http请求. cache-control: cache-control是http协议中常用的头部之一,顾名思义, 他是负责控制页面的缓存机制,如果该头部指示缓存, 缓存的内容也会存在本地, 操作流程和expire相似,但也有不同的地方, cache-control有更多的选项, 而且也有更多的处理方式. if-modified-since 和 last-modified: 当apache接收到一个资源请求(假设是用户是第一次访问,没有任何缓存), 服务器返回资源的同时,还会发送一个last-modified的http响应头, last-modified响应头的内容值是该资源在服务器上最后修改的时间.浏览器接受到这个http头后,会 把其内容值和资源同时保存起来. 当用户第二发送资源请求(假设这里expire没有生效或者已经过期), 浏览器在本地找到了一个相同的资源,但是不能确定该资源是否和服务器上的一样(有可能在两次访问期间,服务器上的资源已经被修改过),此时浏览器发送请求的时候,请求头内会 附带一个if-modified-since的请求头, 这个头部的内容就是上一次last-modified返回的值, 服务器把这个头的值和请求资源的最后修改时间对比,如果两个值相同,则认为资源没有修改,将会返回304,让浏览器使用本地资源.否则服务器将返回资源,而且 返回200状态 if-none-match 和 etag: 其实这两个头部和if-modified-since, last-modified的工作原理是一样的, if-none-match作为请求头, etag作为响应头.既然工作原理一样, 为什么etag这对头部会出现呢? 原因在于, last-modified请求头的内容是以文件最后修改的时间作为对比的,但是unix系统里面, 文件修改的时间只保存到了秒. 如果某些应用内存在1秒内对文件做了多次修改,这样last-modified是不能完成比较功能的.所以要引入一个新的机制(原因可能不止这一个); etag的值一般由3个数值组成,资源的inode值, 最后修改时间, 资源大小,以16进制组成一个字符串, 例如:1a-182b-10f; 但这个格式不是固定的, 只要保证该值的唯一性,但不限格式. 静态资源的更新:张云龙老师的blog写的很好移步这里   html5离线存储 步骤: 1、配置apache让apache支持manifest文件 2、创建manifest文件test.manifest

3、关联manifest文件到html文档

注意:#是用来注释一行的,但它还有一个小作用,web应用的缓存只有在manifest文件被修改的情况下才会被更新,所以如果你只是修改了被缓存的文件,那么用户本地的缓存还是不会被更新的,但是你可以通过修改manifest文件来告诉浏览器需要更新缓存了。利用这点,你可以像上面的例子中那样,写一句这样的注释一个文件版本: # wanz app v1 优点:你可以很明确的了解离线web应用的版本 通过简单的修改这个版本号就可以轻易的通知浏览器更新 你可以配合JavaScript程序来完成缓存更新 CACHE: 这个是manifest文件的默认入口,在此入口之后罗列的文件 (或直接写在CACHE MANIFEST后的文件)在它们下载到本地后会被缓存起来 NETWORK: […]

龙生   13 Oct 2018
View Details

C#中HttpClient使用注意:预热与长连接

原文地址:C#中HttpClient使用注意:预热与长连接 最近在测试一个第三方API,准备集成在我们的网站应用中。API的调用使用的是.NET中的HttpClient,由于这个API会在关键业务中用到,对调用API的整体响应速度有严格要求,所以对HttpClient有了格外的关注。 开始测试的时候,只在客户端通过HttpClient用PostAsync发了一个http post请求。测试时发现,从创建HttpClient实例,到发出请求,到读取到服务器的响应数据总耗时在2s左右,而且多次测试都是这样。2s的响应速度当然是无法让人接受的,我们希望至少控制在100ms以内。于是开始追查这个问题的原因。 在API的返回数据中包含了该请求在服务端执行的耗时,这个耗时都在20ms以内,问题与服务端API无关。于是把怀疑点放到了网络延迟上,但ping服务器的响应时间都在10ms左右,网络延迟的可能性也不大。 当我们正准备换一个网络环境进行测试时,突然想到,我们的测试方式有些问题。我们只通过HttpClient发了一个PostAsync请求,假如HttpClient在第一次调用时存在某种预热机制(比如在EF中就有这样的机制),现在2s的总耗时可能大多消耗在HttpClient的预热上。 于是修改测试代码,将调用由1次改为100次,然后恍然大悟地发现——只有第1次是2s,接下来的99次都在100ms以内。果然是HttpClient的某种预热机制在搞鬼! 既然知道了是HttpClient预热机制的原因,那我们可以帮HttpClient进行热身,减少第一次请求的耗时。我们尝试了一种预热方式,在正式发http post请求之前,先发一个http head请求,代码如下:

经测试,通过这种热身方法,可以将第一次请求的耗时由2s左右降到1s以内(测试结果是700多ms)。 在知道第1次HttpClient请求耗时2s的真相之后,我们将目光转向了剩下的99次耗时100ms以内的请求,发现绝大部分请求都在50ms以上。有没有可能将之降至50ms以下?而且,之前一直有这样的纠结:每次调用是不是一定要对HttpClient进行Dispose()?是不是要将HttpClient单例或者静态化(声明为静态变量)?借此机会一起研究一下。 在HttpClient的背后,有一个对请求响应速度有着不容忽视影响的东东——TCP连接。一个HttpClient实例会关联一个TCP连接,在对HttpClient进行Dispose时,会关闭TCP连接(我们用Wireshark进行网络抓包也验证了这一点)。 在之前的测试中,我们每次用HttpClient发请求时,都是新建一个HttpClient实例,用完就对它进行Dispose,代码如下:

所以每次请求时都要经历新建TCP连接->传数据->关闭连接(也就是通常所说的短连接),而且雪上加霜的是请求用的是https,建立TCP连接时还需要一个基于公私钥加解密的key exchange过程:Client Hello -> Server Hello -> Certificate -> Client Key Exchange -> New Session Ticket。 如果我们想将请求响应时间降至50ms以下,就必须从这个地方下手——重用TCP连接(也就是通常所说的长连接)。要实现长连接,首先需要的就是在HttpClient第1次请求后不关闭TCP连接(不调用Dispose方法);而要让后续的请求继续使用这个未关闭的TCP连接,我们必须要使用同一个HttpClient实例;而要使用同一个HttpClient实例,就得实现HttpClient的单例或者静态化。之前的3 个问题,由于要解决第1个问题,后2个问题变成了别无选择。 为了实现长连接,我们将HttpClient的调用代码改为如下的样子:

然后测试一下请求响应时间:

除了第1次请求,接下来的99次请求绝大多数都在50ms以内。TCP长连接的效果必须的! 通过Wireshak抓包也验证了长连接的效果: 这时,你也许会产生这样的疑问:将HttpClient声明为静态变量,会不会存在线程安全问题?我们当时也有这样的疑问,后来在stackoverflow上找到了答案:

HttpClient的所有异步方法都是线程安全的,放心使用。 到这里,HttpClient的问题是不是可以完美收官了?。。。稍等,还有一个问题。 客户端虽然保持着TCP连接,但TCP连接是两口子的事,服务器端呢?你不告诉服务器,服务器怎么知道你要一直保持TCP连接呢?对于客户端,保持TCP连接的开销不大;但是对于服务器,则完全不一样的,如果默认都保持TCP连接,那可是要保持成千上万客户端的连接啊。所以,一般的Web服务器都会根据客户端的诉求来决定是否保持TCP连接,这就是keep-alive存在的理由。 所以,我们还要给HttpClient增加一个Connection:keep-alive的请求头,代码如下:

现在终于可以收官了。但是肯定不完美,分享的只是解决问题的过程。   from:https://www.cnblogs.com/JustYong/p/5872296.html

龙生   07 Oct 2018
View Details

Github 修正上传时“this exceeds GitHub’s file size limit of 100 MB”错误

Github只允许上传最大100MB的文件,如果超过,则会被server reject 则需: git filter-branch --force --index-filter "git rm --cached --ignore-unmatch FILEPATH"  --prune-empty --tag-name-filter VERSION — --all git commit --amend -CHEAD git push origin master 注意要在.git文件夹目录下执行以上命令 http://www.walbrix.com/jp/blog/2013-10-github-large-files.html from:https://blog.csdn.net/fightforyourdream/article/details/25357121

龙生   07 Oct 2018
View Details

C# HttpClient请求

  from:https://www.cnblogs.com/louby/p/8021527.html

龙生   07 Oct 2018
View Details

c# Http请求之HttpClient

利用HttpClient进行Http请求,基于此,简单地封装了下:

有关更多的Http请求,请看这里:https://github.com/wangqiang3311/HttpRequestDemo from:http://www.cnblogs.com/wangqiang3311/p/8991214.html

龙生   07 Oct 2018
View Details

C# 中使用System.Net.Http.HttpClient 模拟登录博客园 (GET/POST)

一、 System.Net.Http.HttpClient简介 System.Net.Http 是微软.net4.5中推出的HTTP 应用程序的编程接口, 微软称之为“现代化的 HTTP 编程接口”, 主要提供如下内容: 1. 用户通过 HTTP 使用现代化的 Web Service 的客户端组件; 2. 能够同时在客户端与服务端同时使用的 HTTP 组件(比如处理 HTTP 标头和消息), 为客户端和服务端提供一致的编程模型。 个人看来是抄袭apache http client ,目前网上用的人好像不多,个人认为使用httpclient最大的好处是:不用自己管理cookie,只要负责写好请求即可。 由于网上资料不多,这里借登录博客园网站做个简单的总结其get和post请求的用法。 查看微软的api可以发现其属性方法:http://msdn.microsoft.com/zh-cn/library/system.net.http.httpclient.aspx 由其api可以看出如果想设置请求头只需要在DefaultRequestHeaders里进行设置 创建httpcliet可以直接new HttpClient() 发送请求可以按发送方式分别调用其方法,如get调用GetAsync(Uri),post调用PostAsync(Uri, HttpContent),其它依此类推。。。 二、实例(模拟post登录博客园) 首先,需要说明的是,本实例环境是win7 64位+vs 2013+ .net 4.5框架。 1.使用vs2013新建一个控制台程序,或者窗体程序,如下图所示: 2.必须引入System.Net.Http框架,否则将不能使用httpclient 3.实现代码

代码分析: 首先,从Main函数开始,调用LoginCnblogs方法; 其次,使用GET方法:

再者,使用POST方法:

最后,注意其返回值可以是string,也可以是byte[],和stream的方式,这里看你需要什么吧。   4.登录成功后的截图 1).使用浏览器登录后的截图: 2).使用Httpcliet登录后的截图:   总结,可以发现C#中HttpClient的用法和Java中非常相似,所以,说其抄袭确实不为过。   from:https://www.cnblogs.com/amosli/p/3918538.html

龙生   07 Oct 2018
View Details

C# HttpClient设置cookies的两种办法 (转发)

一般有两种办法 第一种handler.UseCookies=true(默认为true),默认的会自己带上cookies,例如

这种情况post请求登陆成功后,重定向到别的页面,也会自动带上cookies。如果把handler.UseCookies设置为false,登陆后重定向的话不会自动带上cookies,则又会跳转到登陆页面。   第二种设置 handler.UseCookies = false时,则需要手动给headers上加入cookies.

如果使用场景是:抓取需要登陆后才能看到的网页数据,建议使用第一种,不需要设置任何cookies,httpclient会自动把登陆后的cookies放置到后面的请求中。   原贴 : http://www.cnblogs.com/xiaozhu39505/p/8033108.html from:https://www.cnblogs.com/refuge/p/8060142.html

龙生   07 Oct 2018
View Details
1 177 178 179 415