使用Node.js搭建静态资源服务详细教程(4)

isFresh(reqHeaders, resHeaders) { const noneMatch = reqHeaders['if-none-match']; const lastModified = reqHeaders['if-modified-since']; if (!(noneMatch || lastModified)) return false; if(noneMatch && (noneMatch !== resHeaders['etag'])) return false; if(lastModified && lastModified !== resHeaders['last-modified']) return false; return true; }

需要注意的是,http首部字段名是不区分大小写的(但http method应该大写),所以平常在浏览器中会看到大写或小写的首部字段。

使用Node.js搭建静态资源服务详细教程

使用Node.js搭建静态资源服务详细教程

但是node的http模块将首部字段都转成了小写,这样在代码中使用起来更方便些。所以访问header要用小写,如reqHeaders['if-none-match']。不过,仍然可以用req.rawreq.rawHeaders来访问原headers,它是一个[name1, value1, name2, value2, ...]形式的数组。

现在来测试一下,因为设置的缓存有效时间是极小的5s,所以强缓存几乎不会命中,所以第二次访问文件会发出新的请求,因为服务端文件并没做什么改变,所以会返回304。

使用Node.js搭建静态资源服务详细教程

现在来修改一下请求的这张图片,比如修改一下size,目的是让服务端的再验证失败,因而必须给客户端发送200和最新的文件。

使用Node.js搭建静态资源服务详细教程

接下来把缓存有效时间改大一些,比如10分钟,那么在10分钟之内的重复请求,都会命中强缓存,浏览器不会向服务端发起新的请求(但network依然能观察到这条请求)。

使用Node.js搭建静态资源服务详细教程

内容编码

服务器在发送很大的文档之前,对其进行压缩,可以节省传输用时。其过程是:

浏览器在访问网站时,默认会携带Accept-Encoding头

服务器在收到请求后,如果发现存在Accept-Encoding请求头,并且支持该文件类型的压缩,压缩响应的实体主体(并不压缩头部),并附上Content-Encoding首部

浏览器收到响应,如果发现有Content-Encoding首部,按其值指定的格式解压报文

对于图片这类已经经过高度压缩的文件,无需再额外压缩。因此,我们需要配置一个字段,指明需要针对哪些类型的文件进行压缩。

default.json

{ ... "zipMatch": "^\\.(css|js|html)$" } static-server.js constructor() { ... this.zipMatch = new RegExp(config.zipMatch); }

用zlib模块来实现流压缩:

compressHandler(readStream, req, res) { const acceptEncoding = req.headers['accept-encoding']; if (!acceptEncoding || !acceptEncoding.match(/\b(gzip|deflate)\b/)) { return readStream; } else if (acceptEncoding.match(/\bgzip\b/)) { res.setHeader('Content-Encoding', 'gzip'); return readStream.pipe(zlib.createGzip()); } else if (acceptEncoding.match(/\bdeflate\b/)) { res.setHeader('Content-Encoding', 'deflate'); return readStream.pipe(zlib.createDeflate()); } }

因为配置了图片不需压缩,在浏览器中测试会发现图片请求的响应中没有Content-Encoding头。

范围请求

最后一步,使服务器支持范围请求,允许客户端只请求文档的一部分。其流程是:

客户端向服务端发起请求

服务端响应,附上Accept-Ranges头(值表示表示范围的单位,通常是“bytes”),告诉客户端其接受范围请求

客户端发送新的请求,附上Ranges头,告诉服务端请求的是一个范围

服务端收到范围请求,分情况响应:

范围有效,服务端返回206 Partial Content,发送指定范围内内容,并在Content-Range头中指定该范围

范围无效,服务端返回416 Requested Range Not Satisfiable,并在Content-Range中指明可接受范围

请求中的Ranges头格式为(这里不考虑多范围请求了):

Ranges: bytes=[start]-[end]

其中 start 和 end 并不是必须同时具有:

如果 end 省略,服务器应返回从 start 位置开始之后的所有字节

如果 start 省略,end 值指的就是服务器该返回最后多少个字节

如果均未省略,则服务器返回 start 和 end 之间的字节

响应中的Content-Range头有两种格式:

当范围有效返回 206 时:

Content-Range: bytes (start)-(end)/(total)

当范围无效返回 416 时:

Content-Range: bytes */(total)

添加函数处理范围请求:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wydpsj.html