6

利用 ETag 优化 Rails 应用

 2 years ago
source link: https://blog.yxwang.me/2012/02/etags-in-rails/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

利用 ETag 优化 Rails 应用

Sat, Feb 18, 2012 • Programming

ETag 是 HTTP 协议的一部分,可以用来检测客户端的缓存是否仍然有效。不少网站都实现了对 ETag 的支持,在 HTTP 响应头中加入当前传送内容的 ETag。以 heroku.com 为例:

$ curl -I www.heroku.com
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 17 Feb 2012 17:36:44 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Etag: "f74bb78aa48d36e6a0b2072a131b20b9"
Cache-Control: public, max-age=300
Content-Length: 15481

可以看到响应头中给出了请求内容的 ETag 为 f74…b9。接下来我们再次向服务器发起请求,并通过 If-None-Match 字段告之服务器我们已经获得过一份 ETag 为 f74…b9 的内容。服务器收到请求并生成页面后,如果发现页面的 ETag 不变,就会返回 304,声明缓存有效:

$ curl -I -H 'If-None-Match: "f74bb78aa48d36e6a0b2072a131b20b9"' www.heroku.com
HTTP/1.1 304 Not Modified
Server: nginx
Date: Fri, 17 Feb 2012 17:37:03 GMT
Connection: keep-alive
Last-Modified: Fri, 17 Feb 2012 17:34:00 GMT
Cache-Control: public, max-age=300
ETag: "f74bb78aa48d36e6a0b2072a131b20b9"

浏览器在访问网页时,记录下上一次服务器返回的 ETag,在下一次访问该网页时发送这个 ETag,这样就能有效的利用本地缓存,减少不必要的网络传输了。

Nginx 和 Apache 都很好的支持了 ETag 功能,它们会为静态资源计算 Hash,并将它作为 ETag 返回给客户端。 而对于 CPU 负载较高的应用,还有一个可以优化的空间。Web 服务器在处理客户端请求时,通常的过程是从数据库读取所需数据,交给模版引擎生成 HTML,计算该页面的 ETag,再回复客户端。事实上所需的数据读取完成后,就足以判断缓存是否有效了。

Rails 早在版本 2.2 就加入了 stale? 方法方便开放人员自定义 ETag。以一个博客文章页面为例,页面内容由文章和评论内容生成,如果这两份内容都没有变化,就可以认为客户端缓存依然有效了:

def show
  @article = Article.find(params[:id])
  @comments = @article.comments.all
  if stale?(:etag => [@article, @comments])
    respond_to do |format|
      # ...
    end
  end
end

除此之外,还可以通过 Last Modified 字段控制缓存有效性,Rails 也同样提供了很方便的支持。但是ETag 方法控制缓存更为精确,而且在服务器时间变化时用 Last Modified 容易出错,因此 ETag 往往是更被推荐的方案。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK