CloudFlareがHTTP/2 Server Pushのサポートを開始した。今のところ、この規模のCDNでServer PushをサポートしているのはCloudFlareぐらいではないかな。Server Pushは「副作用」もあるので万能ではないけど、賢く使えばウェブサイトのパフォーマンスが向上すると思われる。
それで、さっそくServer Pushを試してみようと、適当なアセットをプリロードするLinkヘッダを送信するPHPファイルにアクセスしてみると、確かにファイルがプッシュされたのが確認できた。でも問題発生、完璧じゃない。複数ファイルをプッシュしているのに、なぜだか実際にプッシュされたのは最初に送信したファイルだけ。勿論、PHPのheader関数の二番目のパラメータにfalseを指定し、置換させてもない。はて困った。
ファイル1つに付き、Linkヘッダも1つ
原因を調べようにも、困ったことにCloudFlareは送信したLinkヘッダを除去してしまうので、実際にどんなLinkヘッダが送信されたのかわからない。そこで、X-LOGという適当なヘッダにLinkと同じ値を設定し送信してみた。ブラウザからレスポンスヘッダを確認してみると、この様な値が設定されていた。
X-LOG: <image.png?1>; rel=preload; as=image, <image.png?2>; rel=preload; as=image
なるほど、つまりCloudFlareには「Link: <image.png?1>; rel=preload; as=image, <image.png?2>; rel=preload; as=image」のような値が送信されていたわけだ。これで原因がなんとなくわかってきた。どうやらCloudFlareはプッシュしたいファイルごとにLink:ヘッダを送信する必要があり、カンマ区切りで1つのLink:ヘッダにまとめるというフォーマットに対応していないようだ。
しかし、困った。僕は複数回header関数を呼んでいるので、1つのLinkヘッダにまとめるのは僕がやってるわけじゃない。たぶんPHPかApacheが勝手にやってるんだと思う。そこで、PHPのビルトインウェブサーバーを起動し、どんなヘッダが送信されるかチェックした。ちなみに、このようなファイルだ。
<?php
header("Link: <image.png?1>; rel=preload; as=image", false);
header("Link: <image.png?2>; rel=preload; as=image", false);
?>
<!DOCTYPE html>
<h1>test</h1>
で、送信されたヘッダがこれ
HTTP/1.1 200 OK
Host: localhost:8000
Connection: close
X-Powered-By: PHP/5.6.12
Link: <image.png?1>; rel=preload; as=image, <image.png?2>; rel=preload; as=image
Content-Type: text/html; charset=UTF-8
Link:が1つしか送信されていない。ということは、複数の同じヘッダを1つにまとめるのはPHPが勝手にやっていることらしい。要らないお節介だ。
PHPからはどうしょうもない?
さて、PHPから同一のヘッダを複数送るにはどうしたらいいのだろう?正直お手上げだ。header関数のリファレンスをみてもそんな事わからないし。そもそも、CloudFlareのブログ記事「Using HTTP/2 Server Push with PHP」では普通にheader関数を複数回呼んでいるだけだし。もう訳がわからない。もしかしたら、ウェブサーバーからヘッダを追加するとうまくいくかもしれないけど、そんな意味不明なことしたくない。
この問題はcloudflareブログ記事のコメント欄でも指摘されていて、ClaoudFlareの人も対応中で近いうちになんとかしたいとのことだ。
Right now there is not a way to have multiple items in a single Link header. We are working on a new header type to fix this and should have something in the coming week.
早い内になんとかしてほしいもんだ。
ところで、CloudFlareがpreloadなLink:ヘッダを取り除いているせいで、WordPressからプッシュしようとすると、REST APIが勝手に付加している「Link: <http://example.com/wp-json/>; rel=”https://api.w.org/”」みたいなLinkヘッダも一緒に削除されてしまうことがあるようだ。そこまで実害があるとは思えないけど、中身を見ずに勝手にヘッダを削除するとかひどい話だ。