### 静态文件和主动式文件缓存
你能通过在应用配置中指定 `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](http://nginx.net/)这样的更有利于静态文件 伺服的服务器,你可以将 Tornado 的文件缓存指定到任何静态文件服务器上面,下面 是 FriendFeed 使用的 nginx 的相关配置:
```
location /static/ {
root /var/friendfeed/static;
if ($query_string) {
expires max;
}
}
```