后会无期吗,http
为什么叫后会无期之jshttp解析,相信我们很多人都看过各种各样的http文章教程,但是真的就懂了http了吗,或许别人问起的时候,还是无法具体详细地解释,这让我想起了电影后会无期里面的台词,
从小听了很多大道理,可依然过不好这一生

既然如此,那不如让我们看看http是怎么实现的,对于我们FE来说,最熟悉的语言就是js了,那我们就通过解读jshttp这个一系列js实现的http底层的库来完善我们最后一个技能点吧
jshttp是什么?
Low-Level JavaScript HTTP-related Modules
js实现的底层http相关的库,打开这个库,我们可以发现耳熟能详的的nodejs大大,TJ、Doug Wilson等都是这个系列的维护者,而且这一些库被express、koa各种我们能数的过来的web框架依赖着,是经得起工业考验的,那么接下来的我讲通过解读里面的每个库来加深我们对http的里面每个概念的理解
fresh
这次我们开篇第一章,解读是fresh这个库,首先这个库是干什么的,官方定义
HTTP response freshness testing
用于检验我们的资源是否是新鲜的,说白了,就是用来处理http缓存的库。
说到协商缓存,我们立刻想起Last-Modified 和 Etag,就是这两个返回头,帮助我们在服务器校验文件是否更新了,那服务器是什么校验的呢,那就是我们主角fresh登场了
var reqHeaders = { 'if-none-match': '"foo"' }
var resHeaders = { 'etag': '"bar"' }
fresh(reqHeaders, resHeaders)
// => false
var reqHeaders = { 'if-none-match': '"foo"' }
var resHeaders = { 'etag': '"foo"' }
fresh(reqHeaders, resHeaders)
// => true
我们可以看到,fresh返回false说明资源已经过期了,返回true的时候说明资源没有改变,
talk is cheap, show me the code ---linus
深入代码
首先看下面代码,我们可以看到fresh传入两个参数,reqHeaders是本次发起的请求头,而resHeaders是服务器对应这次请求的返回头,如果同时请求头if-modified-since和if-none-match都没有,那么说明协商缓存失效
function fresh (reqHeaders, resHeaders) {
// fields
var modifiedSince = reqHeaders['if-modified-since']
var noneMatch = reqHeaders['if-none-match']
// unconditional request
if (!modifiedSince && !noneMatch) {
return false
}
....
}
那么如果协商缓存请求头都存在呢,我们先看下是否存在强缓存cache-control:no-cache,如果存在,直接返回false
var cacheControl = reqHeaders['cache-control']
if (cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)) {
return false
}
因为Etag的优先级比Last-Modified高,所以接下来会先校验if-none-match,如果if-none-match存在,且不为'*',
// if-none-match
if (noneMatch && noneMatch !== '*') {
var etag = resHeaders['etag']
if (!etag) {
return false
}
var etagStale = true
var matches = parseTokenList(noneMatch)
for (var i = 0; i < matches.length; i++) {
var match = matches[i]
if (match === etag || match === 'W/' + etag || 'W/' + match === etag) {
etagStale = false
break
}
}
if (etagStale) {
return false
}
}
为*的时候,表示
采用其他方法,尤其是 PUT,将 If-None-Match used 的值设置为 * ,用来生成事先并不知道是否存在的文件,可以确保先前并没有进行过类似的上传操作,防止之前操作数据的丢失。这个问题属于更新丢失问题的一种。
那不为*的时候,我们就要跟服务器将要返回给浏览器的etag进行比较,只有etagStale为true,说明资源改变了,才会返回false
假设etag和if-none-match的值相等,那么我们需要进一步看看是否存在if-modified-since
// if-modified-since
if (modifiedSince) {
var lastModified = resHeaders['last-modified']
var modifiedStale = !lastModified || !(parseHttpDate(lastModified) <= parseHttpDate(modifiedSince))
if (modifiedStale) {
return false
}
}
如果lastModified为false或者modifiedSince的时间早于lastModified的时间,说明资源已经被修改了,直接返回false
那么如果经过上面两步,都没有返回false,说明服务器资源都没有被改变,则直接返回true
总结
怎么样,是不是发现服务器处理缓存也就那么一回事,通过上面的解读,是不是对协商缓存有了更深的理解,因为我们已经深入底层,知道服务器是如何对比文件是否更新了,是不是对接下来的后会无期之jshttp解析系列更有兴趣了,关注我,让我们一起继续接下来的jshttp之旅吧