【问题标题】:Cant cache image content delivered with cfcontent无法缓存与 cfcontent 一起交付的图像内容
【发布时间】:2014-05-06 02:36:55
【问题描述】:

我的一个客户不断抱怨他们的网站不够快...这对我来说有点奇怪,因为几个月前他们雇用我时,他们无法让服务器保持 24 小时运行,因为它缓存太多并且内存不足。因此,我删除了大部分缓存,优化了他们的数据库,将它们放在了至少 5 倍强大的新服务器上(RAM 量和处理器速度——它们现在拥有几乎相同时钟速度的 4 倍处理器) ,并且他们抱怨“我们的网站从未如此缓慢!”。

因此,我正在浏览所有 Google 所说的可以提高性能的事情的清单,希望最终他们会对此感到满意,或者他们会意识到他们的网站正在做很多工作,并且他们的服务器有限制,有些页面需要几秒钟才能加载,就像你不能在一个小时内手工建造整辆汽车一样。我所做的所有研究表明,如果我指定了 Cache-Control、Expires 和 Last-Modified 标头,Firefox 应该使用它的缓存,但无论我如何在 ColdFusion 中设置它们,Firefox 和 Chrome 都拒绝使用缓存。我可以手动设置 304 响应标头,如果尚未缓存图像,这似乎会导致 Firefox 不返回任何内容。 (?!!)

所以我有这个代码。很简单。几乎所有文档都说它应该是。并且 FireBug 始终报告(尽管重新启动、缓存清除、强制重新加载等)内容是在几秒钟前创建的,而不是像我在 cfheader 中设置的 7 天前。另一方面,Chrome 将 Last Modified Date 报告为一周前,但随后报告请求标头中的 max-age 为 0。 (?!!)(在 Chrome devtools 中启用了缓存,所以我知道不是这样。)来自 Chrome 的响应标头显示了正确的 max-age 值。 (编辑:这让我对 FireBug 和 Chrome 的开发者工具中的数据显示感到困惑 - 所以事实证明,是的,两个浏览器都正确接收了响应标头。)

<cfheader name="Content-Type" value="image/png" />
<cfheader name="Cache-Control" value="max-age=604800, private, must-revalidate" />
<cfheader name="Expires" value="#getHTTPTimeString(dateadd('d', 1, now()))#" />
<cfheader name="Last-Modified" value="#getHTTPTimeString(dateadd('d', -7, now()))#" />
....
<cfcontent type="image/png" variable="#toBinary(img)#" />

鉴于 Chrome 正确报告了响应标头,这似乎不像我读过的 HTTP 标准 教程(声称基于标准)所说的那样工作应该工作......但我不能确定。我当然不是 HTTP 专家,所以我可能会忽略一些东西。这不是一个复杂的应用程序。这就是为什么我如此沮丧和扯掉我的头发的原因。

非常感谢任何帮助。谢谢!

编辑

因此,要提供有关已接受答案的更多信息,这是我在 ColdFusion 中的解决方案。上面的代码基本上保持在页面中(例如 index.cfm)。然后利用浏览器返回的缓存提示,我在 Application.cfc 中有类似的东西

<cfcomponent output="false">

    <cffunction name="onRequest" access="public" output="true">
        <cfargument name="targetPage" type="string" required="true" />
        <cfset var modDate = getIfMOdifiedSince() />

        <cfif isDate(modDate) and datediff('d', modDate, now()) lte 7>
            <!--- the browser has a cached copy that's less than a week old, let the browser use it --->
            <cfheader name="Content-Type" value="image/png" />
            <cfheader statuscode="304" statustext="Not Modified" />
        <cfelse>
            <!--- the browser hasn't seen it in 7 days (or possibly ever), return the image --->
            <cfheader name="Last-Modified" value="#getHTTPTimeString(now())#" />
            <cfinclude template="#targetPage#" />
        </cfif>
    </cffunction>

    <cffunction name="getIfModifiedSince" access="private" output="false" returntype="string">
        <cfset var head = getHTTPRequestData().headers />
        <cfreturn iif(structKeyExists(head, "if-modified-since"), "head['if-modified-since']", de("")) />
    </cffunction>

</cfcomponent>

这可能比您需要的要简单一些。这个特定的代码实际上并没有检查图像是否被修改,因为这不是我们真正担心的事情。这个应用程序只提供一组特定的图像,所以我们知道这个应用程序提供的任何东西都是 PNG,所以我们可以安全地将内容类型标题设置为 image/png,因为图像真的不会改变,我不会打扰任何类型的实际日期检查。我可能真的可以让图像无限期地存在,但现在我让浏览器一次拥有它们一周。随着他们业务的增长,我可能会在以后增加该持续时间。

这项工作的真正症结在于,使缓存工作的事情是 onRequest() 方法检查 if-modified-since 请求标头,并且当存在时并在所需的时间跨度内,它通过 NOT 截断整个请求包括目标页面(因此不会执行任何剩余的页面代码),而是仅设置 403 Not Modified 状态响应标头。

从长远来看,正如我所怀疑的那样,这实际上是一件非常简单的事情,显然只是被创建在线教程的人广泛误解。

【问题讨论】:

  • 您是否尝试过像 fusion-reactor.com 这样的分析工具 - 他们有 14 天的免费试用期 - 这可以帮助解决原始错误,允许您删除缓存标头
  • 我们正在服务器上运行 fusion-reactor...但是 CF 没有抛出错误,所以我不确定这有什么帮助?
  • 关于fusion-reactor 的建议是,如果你修复了网站性能不佳的问题,你就不需要那些让你痛苦的缓存标头。修复缓存头实际上并不能修复服务器性能,它只是掩盖了它。
  • 他们的网站是面向公众的吗?你能链接到他们的网站吗?
  • 修复图像缓存将减少服务器上的负载,因此确实总体上具有提高性能的潜力。

标签: performance caching coldfusion


【解决方案1】:

要了解 HTTP,最好直接访问 RFC 2616,或者至少是引用相关部分的教程。

在这种情况下,相关部分是响应头 Last-Modified(第 14.29 节)、请求头 If-Modified-Since(第 14.25 节)和状态 304 Not Modified(第 10.3.5 节)。 (不过,您可能还想阅读其他一些与缓存相关的内容。)

可能最好的演示方式是查看 HTTP 请求/响应的样子。

所以这是对图像的第一个请求(为了清楚起见,剪掉了一堆标题):

GET /res/image.png HTTP/1.1
主机:mydomain.com
用户代理:我是浏览器
接受:*/*

当 URL 为 http://mydomain.com/res/image.png 时,这基本上就是您从浏览器获得的内容。

服务器对其进行解析,找出合适的文件是什么,并做出如下响应:

HTTP/1.1 200 OK
日期:格林威治标准时间 2014 年 5 月 6 日星期二 22:33:44
最后修改时间:2014 年 5 月 3 日星期六 20:00:25 GMT
内容长度:4636
内容类型:image/png;charset=UTF-8

{图像数据}

当浏览器缓存内容时,它会记下 Last-Modified 日期,当它稍后发送请求时,它看起来像这样:

GET /res/image.png HTTP/1.1
主机:mydomain.com
If-Modified-Since:2014 年 5 月 3 日星期六 20:00:25 GMT
用户代理:我是浏览器
接受:*/*

服务器根据文件的修改日期检查 If-Modified-Since,发现没有变化,然后响应:

HTTP/1.1 304 未修改
日期:格林威治标准时间 2014 年 5 月 6 日星期二 22:34:56

当然也不返回图片数据。

(如果有更改,则响应将是 200(具有新的 Last-Modified 值)和新数据。)

【讨论】:

    【解决方案2】:

    如果对 CFContent 交付的网络资产的请求足够多,则可能会发生拒绝服务。如果访问者、机器人或黑客的连接速度很慢(或限制了他们的带宽),您的 ColdFusion 线程将很快填满并排队。

    为什么无法使用 Web 服务器从添加了特殊“7 天过期”标头规则的子目录中提供图像?

    如果图像是唯一的,您可以在离线临时目录中生成它们,设置目录映射,然后使用唯一或基于会话的文件名,并使用计划任务来清理过时的图像。

    延迟加载图像也会使网站的页面加载时间受益。这将加载网页,并且仅加载“首屏”中的可见图像。这可以使用 javascript 来完成。如果你使用 jQuery,这里有一个不错的插件:http://www.appelsiini.net/projects/lazyload

    您是否将 ColdFusion 处理时间添加到生成的 HTML 中?我们在开始和结束时使用 GetTickCount(),然后在 HTML 中将生成时间作为注释发布(执行:163 毫秒)。如果您看到最短时间,那么瓶颈不是 ColdFusion。

    关于网页性能,我使用 Google PageSpeed 取得了巨大成功。 (我在 IIS7 上,所以我不得不使用 IISpeed http://www.iispeed.com/)在我的一个网站上,包含许多产品图片的网页的感知加载时间从 13 秒变为 7.2 秒(-5.8 秒 / 44%更快)。

    https://www.youtube.com/watch?v=VwEGGB-4sMw

    我只用 ColdFusion 测试了 IISpeed。在每个站点的基础上,我们使用 IISpeed 对 ColdFusion 9 生成的页面自动执行以下优化:

    • 组合关键 CSS 并确定其优先级
    • 将脚本上方的 CSS 移到头部
    • 合并、缩小和延迟 JavaScript 并移至头部
    • 扩展缓存(使用哈希缓存资源 1 年,除非更改)
    • 延迟加载图像、Sprite 图像并将 JPEG 转换为渐进式
    • 优化图像(为较小的设备屏幕调整图像大小并将 WebP 提供给 Chomr 浏览器)
    • 折叠空格并删除评论

    要测试您网站的页面加载速度,请使用http://www.webpagetest.org/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-13
      • 2014-04-26
      • 1970-01-01
      • 2018-11-03
      • 1970-01-01
      • 2013-11-28
      • 1970-01-01
      • 2018-04-17
      相关资源
      最近更新 更多