静态文件和主动式文件缓存
你能通过在应用配置中指定 static_path
选项来提供静态文件服务:
settings = {
"static_path": os.path.join(os.path.dirname(__file__), "static"),
"cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",
"login_url": "/login",
"xsrf_cookies": True,
}
application = tornado.web.Application([
(r"/", MainHandler),
(r"/login", LoginHandler),
(r"/(apple-touch-icon\.png)", tornado.web.StaticFileHandler, dict(path=settings['static_path'])),
], **settings)
这样配置后,所有以 /static/
开头的请求,都会直接访问到指定的静态文件目录, 比如 http://localhost:8888/static/foo.png 会从指定的静态文件目录中访问到 foo.png
这个文件。同时 /robots.txt
和 /favicon.ico
也是会自动作为静态文件处理(即使它们不是以 /static/
开头)。
在上述配置中,我们使用 StaticFileHandler
特别指定了让 Tornado 从根目录伺服 apple-touch-icon.png
这个文件,尽管它的物理位置还是在静态文件目录中。(正则表达式 的匹配分组的目的是向 StaticFileHandler
指定所请求的文件名称,抓取到的分组会以 方法参数的形式传递给处理器。)通过相同的方式,你也可以从站点的更目录伺服 sitemap.xml
文件。当然,你也可以通过在 HTML 中使用正确的 <link />
标签来避免这样的根目录 文件伪造行为。
为了提高性能,在浏览器主动缓存静态文件是个不错的主意。这样浏览器就不需要发送 不必要的 If-Modified-Since
和 Etag
请求,从而影响页面的渲染速度。 Tornado 可以通过内建的“静态内容分版(static content versioning)”来直接支持这种功能。
要使用这个功能,在模板中就不要直接使用静态文件的 URL 地址了,你需要在 HTML 中使用 static_url()
这个方法来提供 URL 地址:
<html>
<head>
<title>FriendFeed - {{ _("Home") }}</title>
</head>
<body>
<div><img src="{{ static_url("images/logo.png") }}"/></div>
</body>
</html>
static_url()
函数会将相对地址转成一个类似于 /static/images/logo.png?v=aae54
的 URI,v
参数是 logo.png
文件的散列值, Tornado 服务器会把它发给浏览器,并以此为依据让浏览器对相关内容做永久缓存。
由于 v
的值是基于文件的内容计算出来的,如果你更新了文件,或者重启了服务器 ,那么就会得到一个新的 v
值,这样浏览器就会请求服务器以获取新的文件内容。 如果文件的内容没有改变,浏览器就会一直使用本地缓存的文件,这样可以显著提高页 面的渲染速度。
在生产环境下,你可能会使用nginx这样的更有利于静态文件 伺服的服务器,你可以将 Tornado 的文件缓存指定到任何静态文件服务器上面,下面 是 FriendFeed 使用的 nginx 的相关配置:
location /static/ {
root /var/friendfeed/static;
if ($query_string) {
expires max;
}
}