用Etag实现php-GD创建的图片缓存
转帖,这篇文章是我去年写的。转到新博客里来。。。。。
网站把图片存在数据库里,有的时候比较方便,有的时候就有点麻烦了。。。比如这些图片不经常更改的时候。。
数据库里的图片一般用php的GD库取出来。然后声明图片格式:
1 | header('Content-Type: image/png'); |
进行适当的操作之后,再用
1 | imagepng($im); |
输出到浏览器里面。
这本来是一种很好的方式。。可是我马上发现了,当我刷新页面的时候,图片重新载入了。
然后图片非常大,于是我的网站变得很慢 。
php生成的图片不能像正常放在服务器里的图片一样缓存么?
我在尝试了之后终于找到了解决方案:
HTTP/1.1里面有个东西叫做Etag
,定义为“被请求变量的实体值”。就是指标识客户端正在请求的数据的一个标记(Token一样的东西)。
使用
1 | header('Etag:'.$ETag); |
来设置Etag,其中变量$ETag
为自定义的Etag的值。
在HTTP请求里面,客户端会带上If-None-Match
,内容就是服务器发来的Etag。然后我们只要用php比对一下是不是相同,如果相同就返回304 Not Modified,如果不同就继续返回数据。
HTTP并没有规定Etag应该是什么样的,于是我们可以自己定义Etag的值,只要保证每次更改Etag都不同就可以了。。常见的是使用md5这样的哈希散列值。
php代码非常简单:
1 | $ETag="你自己的Etag"; |
这一段放在最开头就好了。。。
当然其实我不是把它放在最开头的,我用GD的另一个目的是反外链,于是我把它放在了我的反外链代码后面。如果是外链,直接返回替换的图片,然后才进入这一段代码判断是不是可以调用缓存。
写到这里,这一篇就应该结束了,不过我还有两点需要补充:
第一点是——Etag和URL有关,不同的URL上即使是相同的Etag也没有任何意义。只有URL相同,Etag也相同才会调用缓存。这就要求我们不能用post传参。。。
但是Etag并没有说一定只能用在特定的文件上面,Etag什么都可以用,包括图片,音乐,CSS,JS,HTML本身,都可以有一个Etag,然后用Etag来控制缓存。
第二点是——
在我给我的图片输出页加上这样的代码,然后测试的时候,我发现服务器返回的并不是304,而是200。HTTP header信息里面分明写着:
1 | Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0 |
坑爹嘛这是。检查了Apache设置,php设置和.htaccess设置都没发现这东西是从哪里带上的。。。最后我发现。。其实是因为这个php一开头第一个语句:
1 | session_start(); |
php会话信息默认带no-cache头。。
于是如果你的php非要带session_start();
,就像我一样,一定要从SESSION里面拿gid去查询数据库。就要在一开头(session_start
前面)加上:session_cache_limiter('public');
了。
1 |
|
现在是真正的结束了。。
PS。。。。PHP的GD库真是个好东西。。。