【问题标题】:Lift Cookbook Avoiding CSS and JavaScript CachingLift Cookbook 避免 CSS 和 JavaScript 缓存
【发布时间】:2013-07-31 05:14:18
【问题描述】:

我正在尝试对标签使用 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 文件。

【问题讨论】:

    标签: css scala lift


    【解决方案1】:

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

    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 文件,因此您可以稍微概括该代码,或根据您的需要进行调整。有一个chapter on streaming content in the Cookbook

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

    顺便说一句,如果you post to the Lift mailing list,您可能会在这个问题上获得更多关注。不要误会:我非常喜欢 Stackoverflow,但由于 Lift 的历史,您可以在邮件列表中找到查看问题的用户和提交者。

    【讨论】:

    • 这解决了我在尝试实现类似的东西时遇到的问题。然而,由于本书中的重写适用于所有文件类型,我需要对其进行一些修改,使其仅适用于某些扩展名。我创建了一个最终对我有用的要点:gist.github.com/jcern/6274003,如果它有帮助的话。它对指定的扩展使用重写,对于那些没有指定的扩展,默认使用查询参数方法。唯一无法避免的另一个问题是,对 css 文件进行重写会破坏任何相对路径,例如:background-image : url(../images/file.png)
    【解决方案2】:

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

    默认情况下,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 是资源的虚拟版本。这样他们就不必重命名资源本身。

    【讨论】:

    • 目前,我已经实现了您推荐的方法。也就是说,我正在努力实现这个复杂的逻辑,因为至少根据 lift 食谱文本:“请注意,某些代理可能选择根本不缓存带有查询参数的资源。如果这对您有影响,则可以编写自定义代码资源 ID 方法将随机资源 ID 从查询参数中移出并移入路径。”我们的一些客户确实使用代理服务器,我希望创建一个同样适用于他们的解决方案。
    • 好吧,在这种情况下,缓存代理会有额外的负载,但客户端浏览器无论如何都会缓存资源。因此,缓存代理将不那么强大,但一切都会正常工作。不了解其他人,但我个人认为这是绝对可以接受的。
    • 在您描述的场景中,我担心的是,如果代理服务器忽略了附加参数,那么当资产发生变化时,无法强制浏览器重新加载资产。对,还是我在你说的中遗漏了什么?
    • 好吧,但是您的 qoute 另有说明:“某些代理可能选择不缓存资源”。因此,代理不会缓存。所以浏览器总是会得到新的内容,它可以自己缓存。
    • 好点。我已经读了好几遍了,每次都误解了它。我想我现在会采用更简单的方法,直到我发现它会导致问题。谢谢!
    【解决方案3】:

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

    这可以通过 javascript 内联完成。

    <script>
    document.write("<link rel=\"stylesheet\"type=\"text/css\" href=\"/cached/css/standard.css?" + Math.random() + "\" />");
    </script>
    

    【讨论】:

    • 他正在使用 Lift 进行请求重写,因此对/cached/css/F7017951738702RYSX0/standard.css 的请求应该可以从磁盘上的/css/standard.css 位置正确处理。虽然您的解决方案也会达到类似的效果。
    • 啊,谢谢,对不起,我不熟悉升降框架的工作。如果它只是标题中的几个 css 和 js 文件虽然这将是解决问题的简单方法
    猜你喜欢
    • 2018-10-20
    • 1970-01-01
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 2012-08-24
    • 1970-01-01
    • 2014-02-26
    • 2012-05-09
    相关资源
    最近更新 更多