1

我正在尝试对标签使用 data-lift="with-resource-id" 参数,如 Lift Cookbook ( http://cookbook.liftweb.net/#AvoidAssetCaching ) 中所述,以避免浏览器中的资产缓存。我复制了说明书中提供的代码示例并将其修改为我的环境,以便将随机值引入参数路径。

我的资产存储在两个根目录中——一个名为“css”,一个名为“js”,分别用于 css 和 javascript。

我的代码如下所示:

import net.liftweb.http._
import net.liftweb.util._

object AssetCacheBuster {

  def init() : Unit = {
    val resourceId = Helpers.nextFuncName

    LiftRules.attachResourceId = (path: String) => {
      val PathRegex = """\/cached(\/css\/|\/js\/)(\S+)""".r
      try {
        val PathRegex(root, rest) = path
        "/cached" + root + resourceId + "/" + rest
      } catch {
        case e: scala.MatchError => path
      }
    }

    // Remove the cache/{resourceId} from the request if there is one

    LiftRules.statelessRewrite.prepend( NamedPF("BrowserCacheAssist") {
      case RewriteRequest(ParsePath("cached" :: "css" :: id :: file :: Nil, suffix, _, _), _, _) =>
    RewriteResponse("css" :: file :: Nil, suffix)
      case RewriteRequest(ParsePath("js" :: id :: file :: Nil, suffix, _, _), _, _) =>
        RewriteResponse("js" :: file :: Nil, suffix)
    })    
  }
}

例如,我通过如下调用嵌入了 css 文件:

<link  data-lift="with-resource-id" rel="stylesheet" type="text/css" href="/cached/css/standard.css" />

我期望它的工作方式是 attachResourceId 逻辑将通过路径“/cached/css”识别嵌入的css文件并在路径中注入一个唯一值。因此,例如,/cached/css/standard.css 变为 /cached/css/F7017951738702RYSX0/standard.css。通过使用 Chrome 检查元素,我可以看到这确实发生了,所以我相信这按预期工作。

在底部的重写逻辑中,我希望它查找以“/cached/css”开头的请求并删除/cached 和唯一id 组件。通过在调试器中进行跟踪,这似乎也有效。在调试器中,我可以看到它试图重写的结果 url 是“/css/standard.css”。而且我可以验证,如果我在浏览器 URL 中输入此值,该内容确实会得到服务。然而,浏览器显示一个错误(我可以通过 Chrome 的控制台看到)找不到 .css 文件。

4

3 回答 3

2

这就是我认为你所看到的......

通常 Lift 会忽略 CSS 和 JS 文件,它们将由底层引擎提供服务,例如 Jetty 或 Tomcat。这一切都发生在电梯之外。

在这种情况下,重写的最终结果是(例如)对/css/standard.css的请求,这是正确的。但是最终资源正在 Lift 内部进行解析(因为这就是我们所处的位置——重写不是 HTTP 重定向,所以我们留在 Lift 管道中)。由于 Lift 默认不提供这些文件,因此您会看到 404。

这也是/css/standard.css直接在浏览器中为您工作的原因,因为 Lift 忽略了请求,而 Tomcat(或类似的)正在提供内容。

那么为什么它在书中的例子中起作用呢?在这种情况下,该示例适用于/classpath/jquery.js,并且该 URL 是 Lift 知道如何提供服务的内容(通过ResourceServer)。

这是你可以做的事情......

我想说简单的解决方案是教 Lift 如何提供这些文件。您可以通过匹配您关心的路径并流回内容来做到这一点:

LiftRules.statelessDispatch.append {
  case Req("css" :: file :: Nil, "css", _) =>
    () => for (in <- LiftRules.getResource("/css/"+file+".css").map(_.openStream)) 
       yield {
        StreamingResponse(in, () => in.close, size = -1,
          headers = Nil,  cookies = Nil, code=200)
      }
}

这同样适用于 JS 文件,因此您可以稍微概括该代码,或根据您的需要进行调整。Cookbook 中有一个关于流内容的章节

如果这对你有用,请告诉我,我会更新这本书。

顺便说一句,如果您在 Lift 邮件列表中发帖,您可能会得到更多关注。不要误会:我非常喜欢 Stackoverflow,但由于 Lift 的历史,您可以在邮件列表中找到用户和提交者查看问题和问题的地方。

于 2013-07-30T21:14:18.850 回答
1

你真的需要这种复杂的逻辑吗?

默认情况下,lift 的资源看起来像/static/css/example.css?F745187285965AXEHTY=_. 在这种情况下,如果您使用 nginx / jetty / tomcat / Embedded jetty,您将看到一切正常。

原因是 jetty/tomcat/nginx 占用主要资源example.css,而example.css?asdfadf=_不是找不到后者。并且资源?asdfasdf=_ 被浏览器缓存。因此,浏览器会记住完整的 css 地址的内容。

这是避免缓存的常用技术,顺便说一句。它不仅与电梯有关。默认情况下,开发人员会更新资源并编写一些 HTML,例如: 资源的虚拟版本在/static/css/example.css?14哪里。14这样他们就不必重命名资源本身。

于 2013-07-11T12:35:26.503 回答
0

您需要将随机值作为 GET 值而不是路径注入。更改路径将导致找不到文件(除非您每次都将 css 文件动态写入随机位置)。

这可以使用 javascript 内联完成。

<script>
document.write("<link rel=\"stylesheet\"type=\"text/css\" href=\"/cached/css/standard.css?" + Math.random() + "\" />");
</script>
于 2013-07-10T16:02:24.707 回答