SouLogic 灵魂逻辑

两个 Header 的作用

作者:郑凯

其实这两个问题都是受 [url=http://hi.baidu.com/caoz/blog/item/a46234a83b7cc7bacb130cd5.html]caoz 的一篇 blog[/url] 的启发

当一个页面构建完成,到最后 echo 结果的时候,其实还有好几个问题值得考虑。caoz 的例子是,应该先释放掉 mysql 连接,因为 echo 的过程充满不确定性,如果用户机器慢(假设开了 BT 把带宽榨干了,或者各种各样的可能,PHP 是要等用户确实收到才执行完毕的,这个过程可能要数秒,或者干脆超时,导致 mysql 不能及时释放。

注意,PHP 例子涉及到的环境和工具包括 apache 2.2 / php 5.3.1 / ie 8 / curl / ifstat。没在 fastcgi 下试过

[h]ETag[/h]

虽然很早就知道 ETag,但我对 ETag 的认识一直局限于静态文件,比方说 Apache 里的 FileETag 参数。刚刚我才意识到有些动态文件也应该有 ETag,代价是给要 echo 的内容 crc32 一下,回报是如果内容相同,你可以减少输出,也就减少了流量和 PHP 的执行时间。这个提升很小,因此要看命中率来决定是否值得这么做,在某些特殊场合应该很有用。例如某些活动或热帖,会导致大量用户狂按 F5,或者某些页面本来就是 header("Cache-Control: no-cache") 的

这个例子是保证页面每分钟只传输一次。

[phpcode]
$sDate = date("Y-m-d H:i");
$sContent = "[ ETag ] ".$sDate."<!--\n".str_repeat(str_repeat(".", 80)."\n", 1000)."\n-->";

$sETag = "\"".hash("crc32", $sContent)."\"";
header("ETag: ".$sETag);

settype($_SERVER["HTTP_IF_NONE_MATCH"], "string");
if ($_SERVER["HTTP_IF_NONE_MATCH"] == $sETag) {
header("HTTP/1.1 304 Not Modified");
exit;
}

echo $sContent;
[/phpcode]

[h]Content-Length[/h]

如果指定了 Content-Length,则浏览器读到相应数量的内容后断开(没深究是浏览器自己断的还是 Apache 发出 eof 的,而不是一直在等待完成。如果页面本身还要额外做些事情,例如向 mysql/memcache/其他什么接口 发送内容,明确指定 Content-Length 并 echo 完后再继续处理剩下的内容。

下面这个例子中,是否注释掉 header 的结果完全不同

[phpcode]
$sDate = date("Y-m-d H:i:s");
$sContent = "[ Content-Length ] ".$sDate."<!--\n".str_repeat(str_repeat(".", 80)."\n", 1000)."\n-->";

header("Content-Length: ".strlen($sContent));
echo $sContent;

sleep(10);
file_put_contents("access.txt", $sDate);
echo " abc";
[/phpcode]

这跟我以前做过的一个接口很像,两边都走 web 访问,为了提高效率,如果是 add/set 之类的操作,发完 request 不等待 response(哪怕是空值也是要时间的,直接断开,而被请求的页面第一行就是 ignore_user_abort,好能完整的执行操作。因为没在 curl 里找到对应的功能,不得不直接 socket 写一个。