Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章 | https://0x9.me/KMrv3 |
Chap1 发现headers
当我们随便打开一个网址(比如大家经常拿来测试网络的百度)时,打开Network,会看到如下请求头,响应头:
究竟这些headers都有什么用呢? 咱们挨个探个究竟。
Chap2 headers用途
2.1 Content-Type
Content-Type
表示请求头或响应头的内容类型。作为请求头时,利用它可以进行body-parser
。
Sooo~ What is body-parser?
body-parser是node常用的中间件,其作用是:
Parse incoming request bodies in a middleware before your handlers, available under the req.body property.
即在处理数据之前用中间件对post请求体进行解析。
body-parser的例子为:
下面的例子展示了如何给路由添加body parser
。通常,这是在express
中最为推荐的使用body-parser
的方法。
1 | var express = require('express') |
body-parser
核心源码为:
1 | // this uses a switch for static require analysis |
以json
为例:
1 | var contentType = require('content-type') |
可以看出:其背后工作原理就是通过分析请求头中的Content-Type
的类型,根据不同的类型进行相应数据处理,我们自己模拟一下:
step1: 先建立server.js
:
1 | req.on('end',function (params) { |
step2: 客户端模拟请求:
1 | let opts = { |
step3: 测试。
先启动server,再启动client,服务端收到按照application/json
格式解析的数据: { a: 1 } 2
.Content-Type
与body-parser
之间的关系就先分析到这里了。后面我们接着看请求头。
2.2 Range:bytes
请求头通过Range:bytes
可以请求资源的某一部分。利用这个字段可模拟部分读取。如下:
1 | http.createServer(function (req, res) { |
server:
1 | let http = require('http'); |
client:
1 | let opts = { |
分段读取添加暂停功能,监听用户输入
1 | let pause = false; |
测试结果:
分段读取有以下好处:
提高读取速度,多线程并行,分块读取
断点续传
模拟并行下载:
1 | let halfFlag = 20 |
运行结果,会把原文件分成两部分下载到download1.txt和download2.txt。
测试:
理论上,这样的下载方式会比第一种方法节约一半的时间。但是实际中的文件下载怎样实现加速以及并行下载的,还有待考究。
2.3 Cache-Control与Expires之强制缓存
Response Header响应头中Cache-Control: max-age=1233
可以设置相对当前的时间的强制缓存,与它相关的Expires
可以设置某个绝对时间点限定读取缓存的时间。
模拟实现:
1 | let url = require('url'); // 专门用来处理url路径的核心模块 |
测试:
10s内刷新:
2.4 对比缓存之Last-Modified和If-Modified-Since
对比响应头Last-Modified and 与请求头If-Modified-Since,可以通过文件修改时间看文件是否修改,从而决定是重新请求还是走缓存。
模拟如下:
step1 不设置强制缓存
1 | res.setHeader('Cache-Control','no-cache'); |
step2 应用文件修改时间比对是否修改,
1 | res.setHeader('Last-Modified', statObj.ctime.toGMTString()); |
测试:
2.5 对比缓存之Etag和 If-None-Match
对比响应头:Etag 与请求头:If-None-Match,Etag和If-None-Match如果相等,即返回304。
etag如何添加?
根据文件内容,生成一个md5的摘要,给实体加一个标签。
这种方法虽然比较耗性能,但是能够更加精确的对比出文件是否进行了修改。依靠文件修改时间进行对比并不够准确。因为有时文件有改动Last-Modified发生了变化,但是文件的内容可能根本没有变化。所以这种方案要优于2.4.
实现方法:
1 | let rs = fs.createReadStream(p); |
设置Etag
1 | rs.on('end',function () { |
测试:
2.6 Accept-Encoding
依靠请求头: Accept-Encoding: gzip, deflate
, br告诉服务端可接受的数据格式。服务端返回后会把数据格式通过响应格式通过Content-Encoding来标记。
在客户端接受gzip的格式下,后端可通过文件压缩处理传递,提高性能。
node api中提供了zlib模块:
zlib模块提供通过 Gzip 和
Deflate/Inflate
实现的压缩功能
下面我们来应用zlib与请求头Accept-Encoding
来实现压缩功能。
1 | let zlib = require('zlib'); |
解压:
1 | function gunzip(filePath) { |
path.basename(filePath,'.gz')
用来去掉filePath文件名的后缀.gz
。
根据请求头接受的类型后端的具体操作 :
1 | if(req.url === '/download'){ |
1 | let http = require('http'); |
test deflate:
1 | curl -v --header "Accept-Encoding:deflate" http://localhost:3000 |
test others:
1 | curl -v --header "Accept-Encoding:nn" http://localhost:3000 |
2.7 referer
referer表示请求文件的网址,请求时会携带。为了防止自己网站的文件被外网直接引用,可以通过比较referer,即请求的地址,与本地地址比较,设置防盗链。
1 | let http = require('http'); |
2.8 Accept-Language
请求头:Accept-Language: zh-CN,zh;q=0.9
多个语言用 ‘,’ 分隔,权重用 ‘=’ 表示’,没有默认权重为1
后端根据请求接受语言的权重一次查找,查找到就返回,找不到就用默认语言
1 | let langs = { |
测试:
总结
请求头与响应头在前后端联调时会经常使用。了解了他们的妙用前后端配合会更加和谐顺畅~