LoginSignup
34
24

More than 5 years have passed since last update.

日本語URLのデコードに失敗してActionController::BadRequestが発生する場合の対処方法

Posted at

問題

Railsで日本語URLをリンクで使っている場合、たまにデコードできないパラメータを渡されて、ActionController::BadRequestが発生することがある。(userAgent = msnbotのときに多い?)

Controllerのbefore_action等で対処しようとしても、フレームワークの内部でエラーが起きるので、そこまで処理がやってこない。

対処方法

ActionDispatch::Routing::RouteSet::Dispatcher用のモンキーパッチを当てる。

以下のモンキーパッチの例ではデコードに失敗した文字列に空文字をセットしている。(sjisやeucでデコードしても正常な文字列として回復できなかったため)

# config/initializers/active_dispatch_fix.rb
module ActionDispatch::Routing::RouteSet::DispatcherFix
  def call env
    params = env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
    params.each do |key, value|
      unless value.valid_encoding?
        Rails.logger.info "[INFO] Clear invalid value for #{key}"
        params[key] = ''
      end
    end

    super
  end
end

ActionDispatch::Routing::RouteSet::Dispatcher.send :prepend, ActionDispatch::Routing::RouteSet::DispatcherFix

以下はRSpecでテストする場合のサンプルコード。

# spec/requests/examples_spec.rb
require 'spec_helper'

describe 'Examples' do
  context 'with invalid parameter' do
    let(:invalid_path) { '/examples/%E3%E2%80%9A%BD%E3%C6%92' }

    before do
      allow(Rails.logger).to receive(:info)
    end

    it 'handles as RecordNotFound and writes log' do
      expect(Rails.logger).to receive(:info).with('[INFO] Clear invalid value for some_key').once
      expect{ get invalid_path }.to raise_error(ActiveRecord::RecordNotFound)
    end
  end
end

参考文献

Special thanks to

  • @tkawa -- 上記gistのURLを教えてくれました。ありがとうございました。
34
24
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
24