无法缓存cfcontent提供的图像内容

时间:2014-05-06 02:36:55

标签: performance caching coldfusion

我的一位客户不断抱怨他们的网站不够快......这对我来说有点奇怪,因为几个月前他们雇用我时,他们无法让服务器保持运行状态24小时,因为它缓存太多而内存不足。因此,我删除了大部分缓存,优化了他们的数据库,将它们放在一台功能强大至少5倍的新服务器上(RAM的数量和处理器的速度 - 它们的处理器数量是目前处理器数量的4倍)相同的时钟速度),他们抱怨说,#34;我们的网站从来没有如此低调!"。

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

所以我有这个代码。很简单。几乎所有文档都应该是这样的。 FireBug始终报告(尽管重新启动,缓存清除,强制重新加载等)内容是在几秒钟之前创建的,而不是像我在cfheader中设置的那样在7天前创建的。另一方面,Chrome会在一周前报告上次修改日期,但会报告请求标头中的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,因为图像确实没有改变,我&# 39; m不打扰任何实际的日期检查。我可能真的可以让图像无限期地存在,但是现在我让浏览器一次让它们持续一周。随着业务的增长,我可能会延长这段时间。

工作的真正关键在于,使缓存工作的是onRequest()方法检查if-modified-since请求标头,并且当存在并且在期望的时间范围内时,它会截断整个请求。包括目标页面(因此没有剩余的页面代码将执行),而只是设置403 Not Modified状态响应头。

从长远来看,就像我怀疑的那样,它实际上是一件非常简单的事情,显然只是被创建在线教程的人误解了。

2 个答案:

答案 0 :(得分:4)

要理解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
Host: mydomain.com
User-Agent: I'm a browser
Accept: */*

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

服务器解析它,找出适当的文件是什么,并用以下内容作出响应:

HTTP/1.1 200 OK
Date: Tue, 06 May 2014 22:33:44 GMT
Last-Modified: Sat, 03 May 2014 20:00:25 GMT
Content-Length: 4636
Content-Type: image/png;charset=UTF-8

{image data}

当浏览器执行缓存时,它会记录Last-Modified日期,以及稍后发送请求时它看起来像这样:

GET /res/image.png HTTP/1.1
Host: mydomain.com
If-Modified-Since: Sat, 03 May 2014 20:00:25 GMT
User-Agent: I'm a browser
Accept: */*

服务器根据文件的修改日期检查If-Modified-Since,看到没有变化,并回复:

HTTP/1.1 304 Not Modified
Date: Tue, 06 May 2014 22:34:56 GMT

当然不会返回图像数据。

(如果HAD发生变化,则响应为200(带有新的Last-Modified值)和新数据。)

答案 1 :(得分:1)

如果对CFContent交付的Web资产有大量请求,则可能发生拒绝服务。如果访问者,机器人或黑客连接速度较慢(或限制其带宽),您的ColdFusion线程将很快填满并排队。

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

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

网站的页面加载时间也可能因延迟加载图像而受益。这将加载网页,只加载“首屏”中的可见图像。这可以使用javascript完成。如果您使用jQuery,这是一个不错的插件:http://www.appelsiini.net/projects/lazyload

您是否将ColdFusion处理时间添加到生成的HTML中?我们在开始时使用GetTickCount()&amp;结束然后将生成时间作为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生成的页面上自动执行以下优化:

  • 结合&amp;优先考虑关键CSS
  • 将CSS移到脚本以上
  • 结合,缩小&amp;推迟JavaScript&amp;转移到头
  • 扩展缓存(使用哈希缓存资源1年,除非更改)
  • 延迟加载图像,精灵图像&amp;将JPEG转换为渐进式
  • 优化图片(调整较小设备屏幕的图片大小,并将WebP提供给Chomr浏览器)
  • 折叠空白&amp;删除评论

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