Lift Cookbook避免CSS和JavaScript缓存

Lift Cookbook避免CSS和JavaScript缓存,css,scala,lift,Css,Scala,Lift,我正试图使用lift Cookbook()中所述的标记的data lift=“with resource id”参数来避免浏览器中的资产缓存。我复制了cookbook中提供的代码示例,并将其修改到我的环境中,以便在参数路径中引入一个随机值 我的资产存储在两个根目录中——一个叫做“css”,另一个叫做“js”,分别用于css和javascript 我的代码如下所示: import net.liftweb.http._ import net.liftweb.util._ object AssetC

我正试图使用lift Cookbook()中所述的标记的data lift=“with resource id”参数来避免浏览器中的资产缓存。我复制了cookbook中提供的代码示例,并将其修改到我的环境中,以便在参数路径中引入一个随机值

我的资产存储在两个根目录中——一个叫做“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文件。

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

这可以通过javascript内联完成

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

文件。填写(“”);

您真的需要这种复杂的逻辑吗

默认情况下,lift的资源将类似于
/static/css/example.css?F745187285965AXEHTY=quot
。在本例中,如果您使用nginx/jetty/tomcat/embedded jetty,您将看到一切都正常工作

原因是jetty/tomcat/nginx使用主资源
example.css
,而不是
example.css?asdfadf=.
,如果他们找不到后者。浏览器将缓存具有
?asdfasdf=.
的资源。因此,浏览器会记住完整css地址的内容


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

以下是我认为您看到的…

通常,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)
      }
}
LiftRules.statelessDispatch.append{
case-Req(“css”::file::Nil,“css”,417;)=>
()=>for(in.close,size=-1,
headers=Nil,cookies=Nil,code=200)
}
}
这同样适用于JS文件,因此您可以稍微概括一下代码,或者根据需要进行调整。有一个

如果这对你有效,让我知道,我会更新这本书


顺便说一句,如果你有兴趣的话,你可能会在这个问题上吸引更多的眼球。别误会我的意思:我完全喜欢Stackoverflow,但由于Lift的历史,邮件列表是用户和提交者查看问题和问题的地方。

他正在使用Lift进行请求重写,因此对
/cached/css/F7017951738702RYSX0/standard.css的请求应该从磁盘上的
/css/standard.css
位置正确送达。虽然你的解决方案也会达到类似的效果。啊,谢谢,对不起,我不熟悉升降机框架。如果在头文件中只有几个css和js文件,那么现在这将是解决问题的简单方法,我已经实现了您推荐的方法。也就是说,我正在努力实现这个复杂的逻辑,因为至少根据lift cookbook的文本:请注意,某些代理可能会选择根本不缓存带有查询参数的资源。如果这会影响您,那么可以编写一个自定义资源ID方法,将随机资源ID移出查询参数并移到路径中。“我们的一些客户确实使用代理服务器,我希望创建一个同样适用于他们的解决方案。在这种情况下,缓存代理将有额外的负载,但客户端浏览器将缓存资源。因此,缓存代理将没有那么强大,但一切都会正常工作。我不知道其他人的情况,但我个人认为这是完全可以接受的。在您描述的场景中,我担心的是,如果代理服务器忽略附加参数,则无法在资产发生更改时强制浏览器重新加载资产。对,还是我在你说的话中漏掉了什么?好吧,但你的回答不是这样的: