如何使用 Compojure 生成修改后的 http 标头?
我正在尝试提高客户端从我的 Compojure 网络服务器获取页面的性能。我们使用 (compojure.route/resources "/")
提供一堆静态文件(JS、CSS),它在文件系统上查找文件,将它们转换为 URL,然后将它们提供给响如溪流。通过转换为流,似乎会丢失所有文件元数据,例如 mod 时间。
我可以包装静态资源处理程序并添加 Expires
或 Cache-Control: max-age
标头,但这会阻止客户端发送任何请求。很有用,但这些文件有时会发生变化(当我们发布版本时)。
理想情况下,我希望客户端信任自己的缓存版本,例如一个小时,并在该小时过去后使用 If-Modified-Since
标头发出请求。然后我们可以返回304 Not Modified
,客户端就可以避免下载数百公斤的 JavaScript。
看起来我可以在提供响应时设置 Last-Modified
标头,这会导致客户端使用 If-Modified-Since
标头来限定后续请求。太棒了,除了我必须重写 compojure.route/resources 中的大部分代码才能添加 Last-Modified - 不难,但乏味 - 并发明一些更多代码来识别和响应 If-Modified-Since
标头。这不是一项艰巨的任务,但也不是一项简单的任务。
这已经存在于某处吗?我找不到它,但这似乎是一个足够常见、足够大的任务,以至于现在有人已经为它编写了一个库。
I'm trying to improve performance for clients fetching pages from my Compojure webserver. We serve up a bunch of static files (JS, CSS) using (compojure.route/resources "/")
, which looks for files on the filesystem, converts them to URLs, and then serves them to Ring as streams. By converting to streams, it seems to lose all file metadata, such as the mod time.
I can wrap the static-resource handler and add an Expires
or Cache-Control: max-age
header, but that prevents the client from sending any request at all. Useful, but these files do change on occasion (when we put out a release).
Ideally I'd like the client to trust its own cached version for, say, an hour, and make a request with an If-Modified-Since
header after that hour has passed. Then we can just return 304 Not Modified
and the client avoids downloading a couple hundred kilos of javascript.
It looks like I can set a Last-Modified
header when serving a response, and that causes the client to qualify subsequent requests with If-Modified-Since
headers. Great, except I'd have to rewrite most of the code in compojure.route/resources
in order to add Last-Modified
- not difficult, but tedious - and invent some more code to recognize and respond to the If-Modified-Since
header. Not a monumental task, but not a simple one either.
Does this already exist somewhere? I couldn't find it, but it seems like a common enough, and large enough, task that someone would have written a library for it by now.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
FWIW,我通过使用Ring的wrap-file-info中间件来实现这个工作;我有点尴尬,因为我在 Compojure 而不是 Ring 中寻找了这个。然而,
compojure.route
的files
和resources
处理程序都提供流而不是文件或 URL,当然 Ring 无法计算从中取出元数据。我基本上必须编写一个
resources
的副本,它返回一个File
;当包裹在满足我需求的wrap-file-info
中时。仍然不介意一个稍微好一点的解决方案,不涉及从 Compojure 复制一大块代码。FWIW, I got this to work by using Ring's wrap-file-info middleware; I'm sorta embarrassed that I looked for this in Compojure instead of Ring. However,
compojure.route
'sfiles
andresources
handlers both serve up streams instead of Files or URLs, and of course Ring can't figure out metadata from that.I had to write basically a copy of
resources
that returns aFile
instead; when wrapped inwrap-file-info
that met my needs. Still wouldn't mind a slightly better solution that doesn't involve copying a chunk of code from Compojure.您是否考虑过使用ring-etag-middleware?它使用文件的最后修改日期来生成实体标签。然后,它将匹配请求中的 if-none-match 标头时键入 304。
Have you considered using the ring-etag-middleware? It uses the last modified date of a file to generate the entity tag. It then keys a 304 on a match to the if-none-match header in the request.