PUSH
© Steve Snodgrass – “PUSH” – Creative Commons: Attribution

CloudFlareがHTTP/2 Server Pushのサポートを開始した。今のところ、この規模のCDNでServer PushをサポートしているのはCloudFlareぐらいではないかな。Server Pushは「副作用」もあるので万能ではないけど、賢く使えばウェブサイトのパフォーマンスが向上すると思われる。

それで、さっそくServer Pushを試してみようと、適当なアセットをプリロードするLinkヘッダを送信するPHPファイルにアクセスしてみると、確かにファイルがプッシュされたのが確認できた。でも問題発生、完璧じゃない。複数ファイルをプッシュしているのに、なぜだか実際にプッシュされたのは最初に送信したファイルだけ。勿論、PHPのheader関数の二番目のパラメータにfalseを指定し、置換させてもない。はて困った。

ファイル1つに付き、Linkヘッダも1つ

Request Stop
© Martin Lissmyr – “Request” – Creative Commons: Attribution, Noncommercial, No Derivative Works

原因を調べようにも、困ったことに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からはどうしょうもない?

© wong pakman – “Leo – Shiba” – Creative Commons: Attribution, Share Alike

さて、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ヘッダも一緒に削除されてしまうことがあるようだ。そこまで実害があるとは思えないけど、中身を見ずに勝手にヘッダを削除するとかひどい話だ。