12

Ruby on Rails サイトには、パートナーの 1 人が XML データを POST する URI があります。

XML を扱いたくないので、文字通り生データをデータベースの列に詰め込むだけで、それ以上の処理は行いません。

ただし、受け取った投稿の 1 つで、エアブレーキで次のエラーが発生しました。

ArgumentError: invalid %-encoding ("http://ns.hr-xml.org/2004-08-02" 
userId="" password=""><BackgroundReportPackage type="report">
<ProviderReferenceId>....

バックトレースあり:

vendor/ruby-1.9.3/lib/ruby/1.9.1/uri/common.rb:898:in `decode_www_form_component'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:41:in `unescape'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:94:in `block (2 levels) in parse_nested_query'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:94:in `map'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:94:in `block in parse_nested_query'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:93:in `each'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:93:in `parse_nested_query'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/request.rb:332:in `parse_query'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/request.rb:209:in `POST'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/methodoverride.rb:26:in `method_override'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/methodoverride.rb:14:in `call'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/runtime.rb:17:in `call'
vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.13/lib/active_support/cache/strategy/local_cache.rb:72:in `call'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/lock.rb:15:in `call'
vendor/bundle/ruby/1.9.1/gems/actionpack-3.2.13/lib/action_dispatch/middleware/static.rb:63:in `call'
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:136:in `forward'
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:143:in `pass'
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:155:in `invalidate'
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:71:in `call!'
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:51:in `call'
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/engine.rb:479:in `call'
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/application.rb:223:in `call'
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/railtie/configurable.rb:30:in `method_missing'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/deflater.rb:13:in `call'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/content_length.rb:14:in `call'
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/rack/log_tailer.rb:17:in `call'
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:80:in `block in pre_process'
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:78:in `catch'
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:78:in `pre_process'
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:53:in `process'
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:38:in `receive_data'
vendor/bundle/ruby/1.9.1/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run_machine'
vendor/bundle/ruby/1.9.1/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run'
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/backends/base.rb:63:in `start'
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/server.rb:159:in `start'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/handler/thin.rb:13:in `run'
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/server.rb:268:in `start'
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands/server.rb:70:in `start'
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:55:in `block in <top (required)>'
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:50:in `tap'
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:50:in `<top (required)>'
script/rails:6:in `require'
script/rails:6:in `<main>'

問題は、POST に次のデータが含まれていることです。

<ChargeOrComplaint>DRIVE WHILE BLOOD ALCOHOL LEVEL IS 0.08% OR MORE</ChargeOrComplaint>

おそらくこれは有効な XML ですが、HTTP 経由で送信されており、ラックが URL エンコードされていることを期待していると思われるため%、末尾のネイキッドがエラーを引き起こしています。0.08%

バックトレースは、これがコードに到達する前に発生していることを示しているため、処理方法とは関係がないと思います。

私の質問、それから:

1) 問題はどこにあるのか? Ruby 1.9.3 の実装decode_www_form_component(スタック トレースの一番上)? ラック?パートナーの POST データまたはヘッダー? 当店のPOSTの取り扱いは?

2) HTTP 経由で POST された XML データは URL エンコードする必要がありますか?

3) Rack が正しく解釈するために、この POST に必要なヘッダーはありますか? (つまり、XML バイナリ データであり、URL エンコードされていないこと)。

4) パートナーに投稿内容を変更してもらうことができない場合、どうすれば回避できますか? いくつかのラック ミドルウェア?

4

3 に答える 3

8

あなたのパートナーはおそらくデータを「x-www-form-urlencoded」としてあなたに投稿していると思います.Rackはそのように解析しようとします. 送信内容を変更できる場合は、コンテンツ タイプを「text/xml」にすることでこれが修正されると思われます。

送信内容を変更してもらえない場合は、Rack ミドルウェア (またはモンキーパッチ) を使用する必要があると思います。Rack ソースをいじることはできますが、解析を行わないようにする設定があるかもしれません。

于 2013-04-02T17:15:43.557 に答える
2

リクエスト本文のコンテンツで無効なエンコーディング エラーをキャッチする責任がどこにあるのかについて、さまざまなフォーラムでいくつかの議論がありますが、ラックもレールもそれを処理せず、処理はアプリに任せています。アプリの POST データで無効な %-encoding を回避するために、次の関連する質問に対して同様の解決策を使用しました: Rails ArgumentError: invalid %-encoding

app/middleware/invalid_post_data_interceptor.rb無効な投稿データを傍受するために、このミドルウェアを追加しました。

class InvalidPostDataInterceptor
  def initialize(app)
    @app = app
  end

  def call(env)
    request_content = Rack::Request.new(env).POST rescue :bad_form_data

    headers = {'Content-Type' => 'text/plain'}

    if request_content == :bad_form_data
      [400, headers, ['Bad Request']]
    else
      @app.call(env)
    end
  end
end

次に、これを に追加してミドルウェア スタックに追加しますapplication.rb

config.middleware.insert_before Rack::Runtime, "InvalidPostDataInterceptor"
于 2014-07-07T16:29:46.833 に答える
1

私の場合、理由はヘッダーの後とリクエスト本文の前に余分な改行があったことです。パーサーをスローする Content-Length の不一致があると思います。プログラムでヘッダーを設定している場合は、末尾に改行がないことを確認してください。

于 2013-05-02T20:45:02.467 に答える