6月 292012
<< async.jsで非同期処理をまとめる || 画像を安全に埋め込みたい >>
いままでPassenger+Apacheとか、あらかじめforkさせて複数プロセス待機させておくとかしていたから気づかなかった。
Herokuにお金を払ってwebサーバー複数プロセス起動させているなら問題ないと思います。
1リクエストずつしか処理できない
HerokuでRailsやSinatraを使うときは、Rubyで書かれたwebサーバー(thinとか)が1プロセスだけでそのまま動いているのだが、webrick/mongrel/thinあたりは1リクエストずつ順番にしか処理できない。つまりこれとかがそうなんだけど、
http://shokai.herokuapp.com/base64img
リクエスト処理中のアプリ自身にリクエストを送ってしまうと固まってしまう。引数にURLを渡されて別のサイトにHTTPリクエストするのを想定して作られているアプリとかに有り得るミスだと思う。
上は画像のURLを渡されるとbase64encodeしたimgタグを作ってくれるページなんだけど、ここにhttp://shokai.herokuapp.comとか入れると固まるのだった。
(今は固まらないようにしてある)
リクエストうける→自分自身にリクエストしてbase64encodeしようとする→1リクエストずつしか処理できないので、待たされる→最初のレスポンスを返せない!!
となる。
対策
上の画像をbase64エンコードするアプリの例get '/base64img' do
halt 400, 'bad request' if params[:url] =~ /^https?:\/\/#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}/
## 処理続き〜〜
end
こんな感じでリクエスト送る前にチェックしてhaltすると良いと思う。
でもこれだけだとbitly等の短縮URLを使うとすり抜けられる。
どのHTTPライブラリを使うかにもよるけど、自動的に30x系リダイレクト処理をしてくれるライブラリを使う場合はいちいちHTTPヘッダのLocationの指す先を調べないと、HTTPリクエスト処理中の自分自身にHTTPリクエストしてしまう。
ちなみにNode.jsだと複数リクエスト同時に処理できるので全然問題無かった。