【问题标题】:How to properly serve CSS如何正确服务 CSS
【发布时间】:2012-02-26 03:13:36
【问题描述】:

假设我出于某种原因想通过 PHP 提供我的 CSS(因为预处理、合并等)。我需要在我的 PHP 中做什么才能使其正常工作?除了最明显的:

header('content-type: text/css; charset=utf-8');

与缓存、修改时间、etags 等相关的标头呢?我应该使用哪些,为什么以及如何使用?我将如何解析传入的标头并做出适当的响应(例如 304 Not Modified)?


注意:我知道这可能会很棘手,而且在将 CSS 部署为常规 CSS 文件之前,只需对 CSS 执行我想做的事情会容易得多。如果我想那样做,我就不会问这个问题。我很好奇如何正确地做到这一点,并想知道。我事先用 CSS 做什么或可以做什么是无关紧要的;我只是想知道如何正确地为它服务:)

注意 2:我真的很想知道如何正确地做到这一点。我觉得关于这个问题的大部分活动都变成了我为自己为什么要这样做而辩护,而不是获得有关如何做到这一点的答案。如果有人能回答我的问题而不仅仅是建议像 SASS 这样的东西,我将非常感激。我确信它很棒,我可能会在某个时候尝试一下,但这不是我现在要问的。我想知道如何通过 PHP 提供 CSS,并学习如何正确处理缓存和类似的事情。

【问题讨论】:

  • 我完全支持这一事业,即使我们确实有可能更适合该任务的 CSS 预处理器或压缩器。至少,readfile()@import 以简单的方式组合 CSS 文件要快得多,而且人们一直在使用@import
  • 谢谢。似乎一些实际的答案现在已经开始出现在这里! 读取...
  • @WesleyMurch 出于这个原因,这样做的每个人都很清楚:像 LESS 这样的适当预处理器可以让您将多个 CSS 文件预编译成一个文件,因此@import 不是问题。

标签: php css caching header


【解决方案1】:

刚刚解释完了here为什么我认为PHP处理的CSS不是一个好主意;我相信大多数实施它的人会更好地使用另一种应用程序结构。看看吧。

如果您必须这样做,缓存工作将需要独立跟踪每个变体,并让客户端发送一个唯一标识该变体的参数(因此您可以说“未修改”)。

Content-Type 标头是一个好的开始,但不是棘手的部分...

【讨论】:

  • 完全知道这不是棘手的问题,这就是我问的原因:)“跟踪每个变体”是什么意思?什么变种?我现在想做的只是将几个 CSS 文件合并并可能缩小为一个。登录用户或类似用户之间没有差异。每个人都有一个 CSS。
  • @Svish 如果您只是使用 PHP 来组合文件和缩小,那么您应该考虑提前这样做,而不是为每个请求动态地这样做。您的网络服务器会感谢您。
  • @RichBradshaw 看看 Stylus。我以前也用过SASS。
  • @Borealid 如果禁用 Javascript,我的网站会不会看起来很糟糕?
  • @Svish 你有没有试过在禁用 JavaScript 的情况下浏览网页?大多数网站都坏了。无论如何,如果你想让你的样式在没有 JS 的情况下工作,你可以走服务器端编译路线。
【解决方案2】:

一种常见的模式是包含一个无意义的 GET 参数。事实上,堆栈交换站点正是这样做的:

<link ... href="http://cdn.sstatic.net/stackoverflow/all.css?v=0285b0392b5c">

v(版本)可能是某种散列,可能是 css 文件本身。他们不存储旧工作表,这只是一种强制浏览器下载新文件而不使用缓存文件的方法。

使用此设置,将Cache-Control:max-age 设置为较大的值是安全的。

ETag 会让服务器回复304 如果文件没有被修改,你不妨使用相同的哈希:

header('ETag: "' . md5("path to css file") . '"');

【讨论】:

  • ETag 是否由网络服务器透明处理?当浏览器对这个 css 文件进行新的请求时,谁来处理它?谁用 304 回复?我是否必须检查代码中的某些标头或其他内容并检查哈希是否相同或其他内容?
  • @Svish 只要你的 php 脚本作为代理,即使底层服务器确实生成了 ETag,它与 css 文件没有任何关系。当客户端发送最新的ETag时,服务器应该回复304,这也是php脚本应该做的。
  • 不管怎样,v 参数似乎是文件 SHA-1 签名的前 12 个十六进制数字。
【解决方案3】:

值得称赞的努力。缓存的善意太少了。请欣赏我的简短散文,试图在您的道路上为您提供帮助。

总结

发送ETagLast-Modified 标头将使浏览器能够在后续请求中将If-Modified-SinceIf-None-Match 标头发送回您的服务器。然后,在适用的情况下,您可以使用304 Not Modified HTTP 状态代码和空正文(即Content-Length: 0)进行响应。包含Expires 标头将帮助您在内容确实发生变化时提供新的内容。

学徒

听起来很简单,但要做到恰到好处可能有点棘手。幸运的是,有 really good guidance 可用。

一旦您启动并运行它,请转至REDbot,以帮助您消除可能留下的任何粗糙角落。

专家

对于ETag 的价值,您将希望拥有可以复制的东西,但无论何时内容都会改变。否则,您将无法判断传入的值是否匹配。当内容发生变化时仍会更改的可重现值的一个很好的候选者是通过缓存提供的文件的mtime 的 MD5 哈希。在您的情况下,它可能是所有被合并文件的总和。

对于Last-Modified,逻辑答案是所服务文件的实际mtime。为什么忽略显而易见的事情。或者对于一组文件,如您的情况,使用最新的mtime

对于Expires,只需为资产选择适当的TTL 或生存时间。将此数字添加到资产的 mtime 或您为 Last-Modified 选择的值中,您就会得到答案。

您可能还希望包含 Cache-Control 标头,以让可能的代理知道如何正确地为他们的客户服务。

学者

如需更具体的回答您的问题,请参考您之前提出的这些问题:

【讨论】:

  • 谢谢!有很多要研究的,我一定会的。 REDbot 工具似乎也非常方便!
【解决方案4】:

您必须在 javascript 文件的末尾添加查询字符串,这是一个不错的选择,可以说它是新文件,直到浏览器认为相同的 css 文件

www.example.com/css/tooltip.css?version1.0  

www.example.com/css/tooltip.css?12-01-2012

所以浏览器会理解它再次重新加载的这个新文件,将其保存在缓存中直到下一个版本,并且如果您在查询字符串末尾使用 php 附加自动日期,则易于维护。

【讨论】:

    【解决方案5】:

    通过 PHP 提供 CSS(或 JavaScript)的最简单方法是使用 Assetic,这是一个超级有用的 PHP 资产管理器,类似于 Django 的 contrib.staticfiles 或 Ruby 的 Jammit。它处理缓存和缓存失效、动态缩小、压缩以及其他答案中提到的所有“棘手位”。

    要了解如何正确编写自己的资产服务器,我强烈建议您阅读 Assetic 的源代码。它有很多注释和可读性,您将学到很多关于缓存、缩小以及 Assetic 做得很好的所有其他方面的最佳实践。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-19
      • 2016-05-05
      • 2018-09-21
      • 1970-01-01
      • 1970-01-01
      • 2021-06-25
      相关资源
      最近更新 更多