概述
vary 库功能介绍
vary 主要功能是为了方便在响应头上添加 Vary 头信息。
HTTP 响应头 Vary 介绍
响应头 Vary 主要是用于缓存的控制。源服务器会通过 Vary 告诉代理服务器如何使用缓存。
当代理服务器接收到源服务器带有 Vary 响应头的响应后,若要对其进行缓存,则该缓存只对 Vary 指定的请求头字段相同的请求生效。所以即使对相同资源发起请求,但由于 Vary 指定的请求头字段不相同,也无法使用缓存,必须从源服务器中重新获取资源。
基本使用
vary
直接对 response 添加 vary 头信息
// 类型声明
declare function vary(res: ServerResponse, field: string | string[]): void;
// 使用
http.createServer(function(req, res) {
//...
vary(res, 'User-Agent')
//...
})
vary.append
直接在已有的 vary 头信息上添加新的字段信息,合并两个 vary 字段
// 类型声明
declare namespace vary {
function append(header: string, field: string | string[]): string;
}
// 使用
http.createServer(function(req, res) {
//...
const vary = vary.append('Accept, User-Agent', 'Origin')
res.setHeader
//...
})
源码阅读
parse
主要对已有的 vary 字段信息进行结构,由字符串信息变成更好处理的数组。
eg: 'Origin, Accept, Origin'
=> ['Origin', 'Accept', 'Origin']
function parse (header: string): string[] {
var end = 0
var start = 0
var list: string[] = []
// gather tokens
// 类似于词法分析中的直接扫描法
for (var i = 0, len = header.length; i < len; i++) {
// 遍历字符串
switch (header.charCodeAt(i)) {
// 可以忽略字段开头和结尾的空格,但不会忽略字段中间的空格
case 0x20: /* */
if (start === end) {
start = end = i + 1
}
break
// 根据 ',' 拆分字段,并加入集合
case 0x2c: /* , */
list.push(header.substring(start, end))
start = end = i + 1
break
// 正常字符则略过
default:
end = i + 1
break
}
}
// final token
// 可能有残留字段,并加入集合
list.push(header.substring(start, end))
return list
}
vary.append
function append (header, field) {
// 入参校验
if (typeof header !== 'string') {
throw new TypeError('header argument is required')
}
// 入参校验
if (!field) {
throw new TypeError('field argument is required')
}
// get fields array
// 解析需要添加的字段成数组
var fields = !Array.isArray(field)
? parse(String(field))
: field
// assert on invalid field names
// 字段验证
for (var j = 0; j < fields.length; j++) {
if (!FIELD_NAME_REGEXP.test(fields[j])) {
throw new TypeError('field argument contains an invalid header name')
}
}
// existing, unspecified vary
// 如果本来的 vary 是 '*' (所有的请求都被视为唯一并且非缓存的),则忽略合并并返回
if (header === '*') {
return header
}
// enumerate current values
// 解析原有的 vary 字段成数组
var val = header
var vals = parse(header.toLowerCase())
// 与上面一个判断同等意义,如果有 vary 字段为 '*',则直接返回 '*'
if (fields.indexOf('*') !== -1 || vals.indexOf('*') !== -1) {
return '*'
}
// 合并字段
for (var i = 0; i < fields.length; i++) {
var fld = fields[i].toLowerCase()
// append value (case-preserving)
if (vals.indexOf(fld) === -1) {
vals.push(fld)
val = val
? val + ', ' + fields[i]
: fields[i]
}
}
return val
}
vary
function vary (res, field) {
// 判断 res 是否为 SeverResponse
if (!res || !res.getHeader || !res.setHeader) {
// quack quack
throw new TypeError('res argument is required')
}
// get existing header
// 获取原有的 Vary 头信息,并字符串化
var val = res.getHeader('Vary') || ''
var header = Array.isArray(val)
? val.join(', ')
: String(val)
// set new header
// 调用 append 合并字段,并设置为新值
if ((val = append(header, field))) {
res.setHeader('Vary', val)
}
}
参考
下一篇:React 合成事件系统解析