Node.js中的etag包知识学习之express的配置etag
来源:互联网 发布:萧井陌 编程入门指南 编辑:程序博客网 时间:2024/06/09 17:32
原文地址 :阅读原文
API为:etag(entity, [options])
这个方法为给定的实体产生一个strong etag。这个方法必须获取这个实体的完整内容。可以是Buffer,可以是fs.Stats。默认情况下,这个strong etag的产生是不需要fs.Stats的,因为这个fs.Stats会产生weak Etag而不是strong etag,不过这种默认行为可以通过options.weak来覆盖!options:
weak:指定产生的Etag是否会包含弱验证符号(即开头的W/),如果是true那么会包含字符串"W/"。默认是false,除非我们传入的实体是fs.Stats,这时候weak就是true了表示有开头的弱验证符号,而且是通过文件的内容来产生的etag值!
问题1:etag的API中第一个参数是不是必须的?
//必须含有参数 if (entity == null) { throw new TypeError('argument entity is required') }问题2:第一个参数必须是Buffer,fs.Stats或者String?
// support fs.Stats object var isStats = isstats(entity) //判断是否是文件描述符 var weak = options && typeof options.weak === 'boolean' ? options.weak : isStats //如果用户传入了weak,那么用用户的weak为主,否则weak保存的就是是否是文件描述符 // validate argument if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) { throw new TypeError('argument entity must be string, Buffer, or fs.Stats') }
很显然,上面的问题的答案yes。那么他是如何判断一个对象是否为文件描述符呢?
function isstats(obj) { // genuine fs.Stats //判断是否是原生的文件描述符,通过instanceof判断 if (typeof Stats === 'function' && obj instanceof Stats) { return true } // quack quack //n. 庸医;鸭叫声 adj. 骗人的;冒牌医生 vi. (鸭子)嘎嘎叫;吹嘘;大声闲聊 //如果不是原生的文件描述符,那么判断这个对象是否有ctime,同时ctime(change time)是Date对象,是否有mtime,同时mtime(modified time)是Date //是否有ino,而且是number,是否有size同时是number! return obj && typeof obj === 'object' && 'ctime' in obj && toString.call(obj.ctime) === '[object Date]' && 'mtime' in obj && toString.call(obj.mtime) === '[object Date]' && 'ino' in obj && typeof obj.ino === 'number' && 'size' in obj && typeof obj.size === 'number'}很显然是通过instanceof或者判断一个对象的ctime,mtime,ino和size属性来完成的!
问题3:如果是文件描述符和不是文件描述符有什么区别?
var tag = isStats ? stattag(entity) : entitytag(entity) //如果是文件描述符那么用stattag来产生tag,否则用entitytag return weak ? 'W/' + tag : tag如果是文件描述符那么是通过stattag来完成,否则用entitytag来完成的
//如果传入了文件描述符那么获取他的mtime(modified time)和size来产生etag,很显然这时候的etag产生不需要文件的内容 //而只是用文件描述符的mtime和size!function stattag(stat) { var mtime = stat.mtime.getTime().toString(16) var size = stat.size.toString(16) return '"' + size + '-' + mtime + '"'}也就是说如果是文件描述符那么只是用的mtime,size来产生etag!
/** * Generate an entity tag. * @param {Buffer|string} entity * @return {string} * @private */function entitytag(entity) { if (entity.length === 0) { // fast-path empty //如果传入的内容为空那么返回的etag为固定值 return '"0-1B2M2Y8AsgTpgAmY7PhCfg"' } // compute hash of entity var hash = crypto .createHash('md5') .update(entity, 'utf8') .digest('base64') .replace(base64PadCharRegExp, '') //用文件的内容来产生etag,同时取消其中连续的=号! // compute length of entity var len = typeof entity === 'string' ? Buffer.byteLength(entity, 'utf8') : entity.length //如果传入的参数是string那么获取这个string的字节长度,如果不是string那么直接获取他的length属性 return '"' + len.toString(16) + '-' + hash + '"' //所以返回的值为其长度的16进制编码,同时加上内容的hash值!}如果不是文件描述符那么这时候是通过"内容的长度的十六进制+文件内容的md5的16进制来完成的"!
问题4:那么是不是如果是文件描述符就返回mtime+size来返回的etag,否则就返回内容长度的十六进制+文件内容的md5的16进制?
<pre name="code" class="javascript"> var weak = options && typeof options.weak === 'boolean' ? options.weak : isStats return weak ? 'W/' + tag : tag
很显然会有如下的结论:
问题5:为什么要看这部分的原码,为什么要仔细学习etag部分?
这是因为express中的setting中有一个选项就是etag,这个etag的产生就是通过这个包来完成的,我们看看里面他关于etag的配置有那些?
我们看到其中etag可以为布尔值表示是否开启etag,而strong表示开启strong Etag,反之表示weak,当然也可以指定一个函数,这个函数让自己控制对etag的生成!仔细阅读etag
这部分的原码如下:
'use strict'/** * Module exports. * @public */module.exports = etagvar crypto = require('crypto')var Stats = require('fs').Stats//引入node.js的crypto模块和fs模块var base64PadCharRegExp = /=+$/var toString = Object.prototype.toString/** * Generate an entity tag. * @param {Buffer|string} entity * @return {string} * @private */function entitytag(entity) { if (entity.length === 0) { // fast-path empty //如果传入的内容为空那么返回的etag为固定值 return '"0-1B2M2Y8AsgTpgAmY7PhCfg"' } // compute hash of entity var hash = crypto .createHash('md5') .update(entity, 'utf8') .digest('base64') .replace(base64PadCharRegExp, '') //用文件的内容来产生etag,同时取消其中连续的=号! // compute length of entity var len = typeof entity === 'string' ? Buffer.byteLength(entity, 'utf8') : entity.length //如果传入的参数是string那么获取这个string的字节长度,如果不是string那么直接获取他的length属性 return '"' + len.toString(16) + '-' + hash + '"' //所以返回的值为其长度的16进制编码,同时加上内容的hash值!}/** * Create a simple ETag. * * @param {string|Buffer|Stats} entity //第一个参数可以是String,Buffer,Stats * @param {object} [options] //第二个参数是一个对象,其中的weak属性是boolean * @param {boolean} [options.weak] //函数返回值为String * @return {String} * @public */function etag(entity, options) { //必须含有参数 if (entity == null) { throw new TypeError('argument entity is required') } // support fs.Stats object var isStats = isstats(entity) //判断是否是文件描述符 var weak = options && typeof options.weak === 'boolean' ? options.weak : isStats //如果用户传入了weak,那么用用户的weak为主,否则weak保存的就是是否是文件描述符 // validate argument if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) { throw new TypeError('argument entity must be string, Buffer, or fs.Stats') } // generate entity tag var tag = isStats ? stattag(entity) : entitytag(entity) //如果是文件描述符那么用stattag来产生tag,否则用entitytag return weak ? 'W/' + tag : tag}/** * Determine if object is a Stats object. * * @param {object} obj * @return {boolean} * @api private */function isstats(obj) { // genuine fs.Stats //判断是否是原生的文件描述符,通过instanceof判断 if (typeof Stats === 'function' && obj instanceof Stats) { return true } // quack quack //n. 庸医;鸭叫声 adj. 骗人的;冒牌医生 vi. (鸭子)嘎嘎叫;吹嘘;大声闲聊 //如果不是原生的文件描述符,那么判断这个对象是否有ctime,同时ctime(change time)是Date对象,是否有mtime,同时mtime(modified time)是Date //是否有ino,而且是number,是否有size同时是number! return obj && typeof obj === 'object' && 'ctime' in obj && toString.call(obj.ctime) === '[object Date]' && 'mtime' in obj && toString.call(obj.mtime) === '[object Date]' && 'ino' in obj && typeof obj.ino === 'number' && 'size' in obj && typeof obj.size === 'number'}/** * Generate a tag for a stat. * * @param {object} stat * @return {string} * @private */ //如果传入了文件描述符那么获取他的mtime(modified time)和size来产生etag,很显然这时候的etag产生不需要文件的内容 //而只是用文件描述符的mtime和size!function stattag(stat) { var mtime = stat.mtime.getTime().toString(16) var size = stat.size.toString(16) return '"' + size + '-' + mtime + '"'}
0 0
- Node.js中的etag包知识学习之express的配置etag
- ETag
- eTag
- ETag
- 解读前端性能优化之“配置ETag”
- 配置 apache etag
- 52. 配置 Etag (13)
- lighttpd 配置Etag
- HTTP Header中的ETag
- 关于Django中的ETag
- HTTP Header中的ETag
- HTTP Header中的ETag
- HTTP 缓存 之 Etag
- node.js + Express 学习之 环境配置篇
- YSlow—— 配置ETag
- HTTP响应头之ETag
- 学习node+express过程中的MongoDB 的安装配置
- HTTP中的ETag在移动客户端的应用
- HDOJ 1197 Specialized Four-Digit Numbers
- 【LeetCode从零单排(Java)】No2. Add Two Numbers
- SVN的使用方法总结/如何使用TortoiseSVN工具进行版本控制
- arduino的安装
- C++中的复制构造函数
- Node.js中的etag包知识学习之express的配置etag
- 魅蓝 安卓开发调试 无法显示连接解决
- BZOJ 3676: [Apio2014]回文串
- Activities
- AsyncTask异步任务
- eclipse uml 安装
- 一个表单 两个submit
- Java设计模式--单例模式学习笔记
- STL入门