转自http://huacnlee.com/blog/use-etag-in-your-rails-app-to-speed-up-loading/

什么是 ETag

网上关于 ETag 的解释有很多,我这里简单的说明一下我的理解:

ETag 是 HTTP 协议的标准参数,一般是这样的:”686897696a7c876b7e” 一段字符,它能通过一段字符来判断浏览器 cache 的内容是否和服务端返回的内容是否相同,从而来决定是否要重新从服务器下载东西 (HTTP 状态 200 - 重新下载 / 304 - 没有更新)。

ETag 使用场景举例

这个东西非常适合用于动态内容上面,以减少不必要的 HTML 下载,达到加速的目的。

比如下面这个场景的例子:

  1. 用户访问 /topics/11 页面,TopicsController#show 加载 @topic,并通过 View 生成内容返回
  2. 用户来回访问 10 次 /topics/11,可此页面内容无任何变化
  3. 过了1天以后,@topic 有了新的回复,用户再次访问的时候,内容变了

上面的场景用户一共访问了 12 次 /topics/11 这个页面,但只有第一次和最后一次才有实质性的内容需要下载的,可在没有 ETag 的情况下面,服务器执行和浏览器下载都是有 12 次,其中的 10 次是多余的。

如果加上 ETag 以后,将会是这样:

  1. 用户访问 /topics/11 页面,TopicsController#show 加载 @topic,并通过 View 生成内容返回,并给出目前内容的 ETag: 89vbsn28716
  2. 用户带着 ETag: 89vbsn28716 再次访问 /topics/11 ,服务器检查 ETag 与执行结果,发现无变化,返回 304,浏览器直接使用 Cache 的内容渲染页面
  3. 过了一天以后,@topic 有了新回复,用户再次带着 ETag: 89vbsn28716 /topics/11,服务器检查 ETag 发现不对了,生成新内容,并返回 200

这个过程中,服务端执行了 12 次页面,而下载 HTML 内容到本地却只有两次。

Rails 里面开启 ETag

Rails 的 ActionController 里面已经为我们提供了 fresh_whenstale? 这两个方法用于处理 ETag,可以点击连接稍微看一下说明。

我下面以 Ruby China查看 Wiki 页面 为例子演示如何在 Rails 里面合理的使用 ETag

pages_controller.rb:

1
2
3
4
5
6
7
class PagesController < ApplicationController
def show
@page = Page.find_by_slug(params[:id])
@comments = @page.comments.paginate(:page => params[:page], :per_page => 50)
fresh_when(:etag => [@page, @comments])
end
end

加上 fresh_when 方法以后,Rails 将会用 @page@comments 内容的组合的 MD5 hash 值作为 ETag 并与 HTTP Headers 里面的 ETag 进行比较来决定是否需要执行后面的 Views 渲染,并返回 200304

在浏览器上面显示将会是这样:

没有 ETag 的情况 (72 ms):

有 ETag 的情况 (40 ms):

OMG! 页面加载速度直接提升了 46%,并且 ETag 命中的情况下,Views 上面的一系列代码都不用执行了,节省了不少资源。

但是实际的场景,往往没有上面这个例子这么简单……

比如,页面上有 current_user 的状态,页脚的 HTML 代码是通过 Setting.footer_html 出来的,Head 里面还有 Setting.custom_heads 出来的代码。

以上这些东西都是需要影响页面更新的。

实际上我们只需要将 fresh_when 方法在 ApplicationController 里面覆盖一下,把页面上需要调用而影响结果的东西加入到 fresh_when:etag 参数里面就好了:

application_controller.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def fresh_when(opts = {})
opts[:etag] ||= []
# 保证 etag 参数是 Array 类型
opts[:etag] = [opts[:etag]] if !opts[:etag].is_a?(Array)
# 加入页面上直接调用的信息用于组合 etag
opts[:etag] << current_user
# Config 的某些信息
opts[:etag] << SiteConfig.app_name
opts[:etag] << SiteConfig.custom_head_html
opts[:etag] << SiteConfig.footer_html
opts[:etag] << SiteConfig.google_analytics_key
# 所有 etag 保持一天
opts[:etag] << Date.current
super(opts)
end

这样一来,每个用户的 ETag 都是不同的,当用户登出和登录以后,页面的内容将会呈现不同的 ETag,同时当你修改 SiteConfig 的某些内容是,ETag 也会随着改变,这样一来 ETag 的引入就不会影响到页面更新了。

实际上你可以大量的使用 fresh_when 方法在你的动态页面上面,来减少 Rails View 的执行与 HTML 下载,只要好好分析,将页面上需要的内容加入到 :etag 参数里面就好了。

比如:

1
2
3
4
5
6
7
def index
@hot_topics = Topic.hot.limit(10)
@hot_users = User.hot.limit(10)
@hot_nodes = Node.hot.limit(10)
@recent_topics = Topic.recent.limit(10)
fresh_when(:etag => [@hot_topics,@hot_users,@hot_nodes,@recent_topics])
end

在你的 Rails App 中开启 ETag 加速页面载入同时节省资源的更多相关文章

  1. APP中内嵌H5页面为什么不能下载?

    在APP中内嵌H5页面,若页面上存在下载链接,没有任何反应,为什么呢? 原因是app中内嵌的H5页面是WebView解析的,什么是WebView呢? 在Android手机中内置了一款高性能webkit ...

  2. 安卓app中嵌入一个H5页面,当手机系统设置字体变大时,如何使H5页面的字体不会随用户自己调整的系统字体变化而变化?

    webview.getSettings().setTextZoom(100);WebView加上这个设置后,WebView里的字体就不会随系统字体大小设置发生变化了. https://segmentf ...

  3. 用Chrome devTools 调试Android手机app中的web页面。

    (1) 手机要满足Android系统为4.4或更高版本,低版本不支持这种方式.(2) 确保App已经开启了webview的debug调试模式,由Android工程师协助.(2) 用usb数据线连接好手 ...

  4. APP中一种在Java层实现的简单守护进程方式

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52779986 守护进程是一个黑色 ...

  5. ViewPager封装工具类: 轻松实现APP导航或APP中的广告栏

    相信做app应用开发的,绝对都接触过ViewPager,毕竟ViewPager的应用可以说无处不在:APP第一次启动时的新手导航页,APP中结合Fragment实现页面滑动,APP中常见的广告栏的自动 ...

  6. 我刚知道的WAP app中meta的属性

    之前我一直做的都是WEB前端开发,来北京以后面试了一个移动前端开发,WAP前端开发. 其实在原来公司的时候也做过这方面的开发,可面试的时候面试官问我,要想强制让文档与设备的宽度保持1:1,mate标签 ...

  7. 我刚知道的WAP app中meta的属性(转载)

    之前我一直做的都是WEB前端开发,来北京以后面试了一个移动前端开发,WAP前端开发. 其实在原来公司的时候也做过这方面的开发,可面试的时候面试官问我,要想强制让文档与设备的宽度保持1:1,mate标签 ...

  8. 在pycharm_2018.2版本中开启Flask的debug的方法 (不要用命令:python **.py启动)

    断点后,先ctl+c关闭控制台程序,再点击debuger调试 问题描述:在pycharm_2018.2版本中,我明确开启了debug,代码如下所示: from flask import Flask a ...

  9. Hybrid App中原生页面 VS H5页面(分享)

    本文部分转自  http://www.jianshu.com/p/00ff5664e000 现有3类主流APP,分别为:Web App.Hybrid App(混合模式移动应用,Hybrid有“混合的” ...

随机推荐

  1. 译:微软发布.NET应用架构指南草案

    原文<Microsoft Announces Draft .NET Architecture Guidance> 译注:上周微软发布了全新的<.NET应用架构指南>草案,以征求 ...

  2. 使用nexus来搭建Nuget私服

    近期在搭建nuget私服.选择nexus这个产品.nexus支持npm,.nuget等,功能比较强大. 前言 博主使用centos7.5来搭建nexus,遇到了不少的问题.最后还是搞定了. 1:下载n ...

  3. mysql之使用centos7实现主从复制(读写分离)的实现过程

    什么是主从复制? 主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库:主数据库一般是准实时的业务数据库. 主从复制的作用(好处)! 1.做数据的热备,作为后备数据库,主数据库服务器故 ...

  4. WPF之坑——surface触控失灵之谜

    本次又遇到了WPF编写触控程序的一个问题,虽然已解决,但原因确搞不太明白,希望有大神看到这篇文章帮我解答. 在项目中实现了自己定义的icommandsource,因为需要对触控有特殊需求,控件对鼠标与 ...

  5. .Net 百度经纬度转高德

    1.需求 由于我们项目里面的经纬坐标是百度的,而对接的第三方需要的是高德的经纬坐标,两者之间是有位差区别的,不能直接使用,我们需要通过一个算法将百度经纬度转化为高德经纬度,在百度官网上,有java算法 ...

  6. westrac server security configure user info

    security userkey:westracpass:Set#@!123

  7. ko内核模块文件以及载入模块命令modprobe insmod

    原文链接:https://blog.csdn.net/evenness/article/details/7655921?utm_source=blogxgwz5 modprobe: Load modu ...

  8. FFMpeg音频重采样和视频格式转

    一.视频像素和尺寸转换函数 1.sws_getContext : 像素格式上下文  --------------->多副图像(多路视频)进行转换同时显示 2.struct SwsContext  ...

  9. 4、Orcal数据库dmp文件导入

    1.CMD命令导入备份数据库dmp文件: 以上一篇博客提到的gdnh用户,我们需要在cmd窗口执行如下命令: imp gdnh/admin123@orcl file=E:/createTable.dm ...

  10. KMP Demo

    The key of Kmp is to build a look up table that records the match result of prefix and postfix. Valu ...