読者です 読者をやめる 読者になる 読者になる

ジンジャー研究室

長めのつぶやき。難しいことは書きません。

HTTP/2のサーバープッシュを自動化するNode.jsライブラリを作った

そろそろRFCとして公表されるHTTP/2ですが、GoogleがHTTP/2を使ったRPCフレームワークを出してみたりとか、その界隈は大盛り上がりですね!

HTTP/2の目玉機能と言ったら、やっぱりPUSH_PROMISE!

f:id:jinjor:20150227224512p:plain:w340

PUSH_PROMISEと言えば、「index.htmlが必要だったらapp.jsとかstyle.cssも要るよね!」とサーバ側で勝手に判断して送りつける、というのが良くある説明なのだが、それを自動でやってくれるわけではないので、Node.jsサーバ用にライブラリを作ってみた。

jinjor/auto-push · GitHub

npmにもpublishしたので、npm install auto-push可能。

やっていることは、レスポンスの直前にHTMLをパースして、必要そうなJavaScriptなりCSSなり画像なりをプッシュする。それだけ。

HTML Importsにもたぶん対応してるけど、まだちゃんとテストしていない。

サーバーに組み込む

典型的な使い方。

var fs = require('fs');
var autoPush = require('auto-push');
var http2 = require('http2');
var ecstatic = require('ecstatic');

var options = {
  key: fs.readFileSync(__dirname + '/ssl/key.pem'),
  cert: fs.readFileSync(__dirname + '/ssl/cert.pem')
};

http2.createServer(options, autoPush(ecstatic(__dirname + '/public'))).listen(8443);

Express.js上でもいけると思ったけど意外とトラブルに見舞われているので、対応にはもう少しかかりそう。

プロキシとして使う

var autoPush = require('auto-push');
var http = require('http');
var ecstatic = require('ecstatic');
var request = require('request');
var fs = require('fs');
var http2 = require('http2');

// server
http.createServer(ecstatic(__dirname + '/public')).listen(8080);

// proxy
var options = {
  key: fs.readFileSync(__dirname + '/ssl/key.pem'),
  cert: fs.readFileSync(__dirname + '/ssl/cert.pem')
};
http2.createServer(options, autoPush(function(req, res) {
  request({
    method: req.method,
    url: 'http://localhost:8080' + req.url,
    headers: req.headers
  }).pipe(res);
})).listen(8443);

プロキシならNode.js以外のサーバにも対応できる。

課題

304(Not Modified)をどう扱えばいいのか分からない。 具体的には、クライアントから直接リクエストされたもの以外のif-modified-sinceヘッダ情報が無いので、適当にHTMLファイルと同じ情報を使いまわすとまあバグる。 仕方が無いので、現在は更新があろうと無かろうと200で送り返すという雑なことをしている。

その辺の仕様的に妥当な処置とか、教えてもらえたら喜びます。

まとめ

たぶん既に誰かやってるとは思う。