webrickでリダイレクトするときの注意
久々にはてなダイアリーの「日記を書く」を押すとエディタが変わってました。
どうもお久しぶりです。
最近は社内や派遣先でrubyの勉強会を定期的に開いたりしてruby漬けの毎日です。
その勉強会のネタにしようと以前書いた「IronRubyでWindowsのサービスをコントロールする」を見ながらコードを検証していたのですが、FirefoxやChromeでうまく動作しないことが分かりました。現象としてはページ上のリンクをクリックしても内部の処理が行われず、結果表示ページにリダイレクトされてしまうというものです。コードを最小限にして検証してみたのですがこれはIronRubyだけの問題ではなくRubyでも同様の問題が発生するようです。
「301 リダイレクトをchromeがキャッシュする」という記事を読むと、リダイレクトを一度行うとURLに対してリダイレクト先をブラウザが記憶してしまうようです。確かにリダイレクト時に設定する「HTTPStatus::MovedPermanently」は恒久的なページの移動を表すものなのでWebブラウザが記憶してしまうのも分かります。
回避方法としてヘッダーにPragma: no-cacheを付けることにしました。
以下が修正したコードです。
web.rb
require 'webrick' require 'erb' require 'System.ServiceProcess' require 'uri' include System::ServiceProcess include WEBrick server = HTTPServer.new({ :Port => 8080, :BindAddress => '127.0.0.1', :MimeTypes => HTTPUtils::DefaultMimeTypes.merge({"rhtml"=>"text/html"}), :DocumentRoot => Dir.pwd}) class ListServlet < HTTPServlet::AbstractServlet def do_GET(req, res) @services = ServiceController.GetServices.sort_by{|x| x.display_name} open('list.rhtml') do |f| e = ERB.new(f.read) res.body = e.result(binding) end res['Content-Type'] = "text/html" end end server.mount("/list", ListServlet) server.mount_proc("/start") { |req, res| service = ServiceController.new(File.basename(URI.parse(req.path).path)) service.start service.WaitForStatus(ServiceControllerStatus.Running) res['Pragma'] = 'no-cache' #追加 res.set_redirect(HTTPStatus::MovedPermanently, '/list') } server.mount_proc("/stop") { |req, res| service = ServiceController.new(File.basename(URI.parse(req.path).path)) service.stop service.WaitForStatus(ServiceControllerStatus.Stopped) res['Pragma'] = 'no-cache' #追加 res.set_redirect(HTTPStatus::MovedPermanently, '/list') } trap('INT') { server.shutdown } server.start
ブラウザの履歴を削除してから動かすとちゃんと動作しました。
Railsではリダイレクトは日常的に使ってるからブラウザにキャッシュしない仕組みがすでに入っているんでしょうね。