HTTP 提供了许多页面缓存的方案,其中属 Etag 和 Last-Modified 应用最广。本文会先介绍 Etag 的应用场景,然后说说他在 php 和 node 中的使用。

本文地址:http://www.cnblogs.com/hustskyking/p/etag-in-node.html,转载请注明源地址。

一、Etag的使用

客户端和浏览器之间的交互:

+---------+                +---------+
| |---------------->| |
| | (,OK) | |
| |<----------------| |
| 客 | (Etag) | 服 |
| |---------------->| |
| 户 | () | 务 |
| |<----------------| |
| 端 | (强制刷新) | 端 |
| |---------------->| |
| | (,OK) | |
| |<----------------| |
+---------+ +---------+
<Created By Barret Lee>

1. 客户端向服务器请求资源S

2. 服务器返回数据,并带上一个 Etag

3. 客户端再次请求资源S,由于上次服务器给他返回了一个 Etag,这次请求的时候他会带上这个 Etag

4. 服务器发现请求中包含 Etag,判断是否过期,没过期则返回 304 Not Modified

5. 客户端强制刷新(如chrome中ctrl+shift+R刷新页面),请求中剔除 Etag

6. 服务器未发现请求中包含 Etag,返回资源S,并带上一个 Etag

二、代码实现

第一次请求数据:

浏览器在接受到服务器发过来的 Etag 后,会保存下来,下次请求的时候会将它放在请求头中,其 key 值为 If-None-Match。

服务器拿到 If-None-Match 之后,对比之前的 Etag,如果没变,则返回 304 Not Modified.

1. php 中的 Etag

<?php
$str = "Barret Lee";
$Etag = md5($str); if(array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER) and $_SERVER['HTTP_IF_NONE_MATCH'] == $Etag){
header("HTTP/1.1 304 Not Modified");
exit();
} else {
header("Etag:" . $Etag);
echo $str;
}
?>

Etag 是一个字符串,我们一般使用该请求对应响应输出的 md5 值作为 Etag,可以简单地理解为文件的版本号。在 php 中存在两个获取 md5 的函数,一个是针对字符串的,就是 md5(),然后就是针对文件的, md5_file()

首先判断在请求中是否包含 'HTTP_IF_NONE_MATCH' 这个 key,如果包含并且其值为之前的 md5 值,则返回 304,否则输出 Etag 以及内容。

2. node 中的 Etag

与 php 有些不同,从 $_SERVER 中拿到的内容是经过 apache 包装过的,而 node 获取的数据是最原始的。

var hashStr = "A hash string.";
var hash = require("crypto").createHash('sha1').update(hashStr).digest('base64'); require("http").createServer(function(req, res){
if(req.headers['if-none-match'] == hash){
res.writeHead();
res.end();
return;
}
res.writeHead(200, {
"Etag": hash
})
res.write(hashStr);
res.end();
}).listen(9999);

上面对 hashStr(输出的内容) 进行了简单的处理,并将其作为 Etag 放在 head 中输出,上面的代码一目了然,我就不解释了。

三、小结

Etag 在缓存处理中用的比较广泛,使用它可以减少一些不必要请求的带宽的占用。服务器输出的内容不变,浏览器就应该使用缓存,没必要每次都向服务器端索要数据,造成不必要的浪费。

从上面我们可以看到,如果想拿到 Etag,就必须先拿到要输出的数据,所以 Etag 只能减少带宽的占用,并不能降低服务器的消耗。如果是静态页面,可以判断文件最近一次的修改时间(Last-Modified),获取文件上次修改时间的消耗比拿到整个数据的消耗要小的多。所以很多时候 Etag 都是配合这 Last-Modified 一起使用的。

上面的 php 和 node 代码演示,很明显的差异就是,node 更加细致,或者说他更加底层,我们可以获取的几乎都是未加修饰的原始数据,从数据量的交互和可操控性来看,我更偏向于 node 的使用。

Etag缓存在PHP和NodeJS中的实现的更多相关文章

  1. nodejs中获取时间戳、时间差

    Nodejs中获取时间戳的方法有很多种,例如: new Date().getTime() Date.now() process.uptime() process.hrtime() 平时想获取一个时间戳 ...

  2. 在Nodejs中如何调用C#的代码

    最近需要在Nodejs中用到C#的代码,从网上了解到可以采用Edgejs来实现Nodejs与C#的代码交互, 直接复制网上的代码运行总是出各种错,填了不少坑,现在把自己的案例代码大致整理一下,方便以后 ...

  3. nodejs 中自定义事件

    经常看到 req.on('error', function(){...}); 这种代码. 在nodejs中,可以使用 EventEmitter来实现. 具体的关键词有如下几个: var reqEven ...

  4. NodeJS中的异步I/O、事件驱动

    nodejs的主要特点是单线程.异步I/O.事件驱动.让我们先大概了解一下这些名词的意思. 单线程 单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行.在 ...

  5. nodejs中Stream的理解

    在nodejs中可以通过fs模块读写文件,我们来看下fs模块提供的接口: fs.readFile(filename, callback) 异步读取文件. filename是读取文件的文件名,如果是相对 ...

  6. Nodejs中的this

    以下内容都是关于在nodejs中的this而非javascript中的this,nodejs中的this和在浏览器中javascript中的this是不一样的. 在全局中的this console.l ...

  7. 探讨Nodejs中的作用域问题。

    在JS中有全局作用域和函数作用域,而在Nodejs中也自己的作用域,分为全局作用域(global)和模块作用域. js作用域: 以前学js的时候我们的全局对象是window,如: var a = 10 ...

  8. nodejs中exports与module.exports的实践

    只要是在nodejs中写自己的文件模块就少不了会遇到module.exports和exports的使用,看别人的代码大多都会使用“module.exports=exports=<对象/函数等&g ...

  9. 详细讲解nodejs中使用socket的私聊的方式

    详细讲解nodejs中使用socket的私聊的方式 在上一次我使用nodejs+express+socketio+mysql搭建聊天室,这基本上就是从socket.io的官网上的一份教程式复制学习,然 ...

随机推荐

  1. Markdown: 用写代码的思维写文档

    作者:吴香伟 发表于 2014/08/07 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 本文不讲解Markdown的语法规则,只关注它带来的好处以及我使用的方 ...

  2. 一点一滴学shell-Shell expr的用法 (转)

    原文链接:http://desheng666.blog.163.com/blog/static/4908408220121643953425/ expr命令一般用于整数值,但也可用于字符串.一般格式为 ...

  3. mac iterm2配置

    iterm2的配置分为如下几个部分: 1. 字体大小的配置: iTerm->Preferences->Profiles->Text->Regular Font: 我在这里设置成 ...

  4. app开发遇到问题及解决

    1:ios and Android 差异input type=text 当用户点击input框时,弹出手机键盘,ios会遮挡输入框 解决办法: pswOnFocus = function(){ tar ...

  5. ServiceStack.OrmLite中的一些"陷阱"(3)

    前文说到如果使用多数据库(不同SQL方言)时要如何开发?其实前文(第二篇)也有“透露”到.就是直接使用库提供的OrmLiteConnection 及OrmLiteConnectionFactory(I ...

  6. [C#基础实例]指定地址解析图片并下载

    需求:查找页面图片并下载至本地: 实现: 首先:读取通过网络html内容,并用正则表达式查找图片地下. 其次:使用WebRequest.Create创建图片请求. 最后:把获取图片网络流数据通过Fil ...

  7. python 跨模块实现按照文件大小,日期实现日志分割,反转

    笔者的一个自动化测试平台项目,采用了python作为后端服务器语言.项目基于快速成型目的,写了一个极其简陋的日志记录功能,支持日志记录到文件和支持根据日志级别在终端打印不同颜色的log.但随着测试平台 ...

  8. 说说Python中的闭包 - Closure

    转载自https://segmentfault.com/a/1190000007321972 Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西 ...

  9. Sprint评审会议不是Sprint演示会议

    最近,Innolution公司的执行总监.Essential Scrum的作者Ken Rubin在其公司博客上撰写了一篇题为It’s a Sprint Review Not a Sprint Demo ...

  10. 了解及使用IPV6

    1. 什么是 IPv6 IPv6指互联网协议(IP)第6版.目前大家上网主要使用互联网协议第四版,即IPv4. 在全球互联网高度发展的今天,IPv4 地址资源已经枯竭,互联网正在经历从IPv4网络向I ...