LoginSignup
15
16

More than 5 years have passed since last update.

AngularJS x Rails - $httpモジュールからの XHR が text/html と認識されちゃう問題

Last updated at Posted at 2014-06-19

AngularJSの$resourceでRailsアプリのAPIを呼び出した際、なぜかrequest.formatstext/html と認識されちゃう問題の解決策。

コントローラで respond_to json: xxx としているのに、なぜかHTMLがレスポンスされるので解決方法を調べた。

TL;DR

AngularJS側で以下のconfigをするだけ。

$httpProvider.defaults.headers.common["Accept"] = 'application/json';

原因

AngularJSのAcceptヘッダのデフォルト値と、RailsのMIME Type解決のロジックが組み合わさって起こる。

AngularJS

ここに書かれている通り、$httpモジュールのAcceptヘッダのデフォルト値は application/json, text/plain, */*
さらに、X-Requested-Withヘッダも送信しない仕様になっている。

Rails

Rails/actionpackのMIME Type解決をしている部分で、Acceptヘッダに*/*が含まれるとブラウザからのアクセスとみなされてMIME Typeが強制的にtext/htmlに設定される。(このロジックが導入された時のコミットログ*/*はブラウザしか使わないはずだから、とりあえずHTML送りつけとくぜ、的な。)
また上記の通りAngularJSからはX-Requested-Withヘッダも送信されないため、MIME Typeが期待通りに解釈されない。

actionpack/lib/action_dispatch/http/mime_negotiation.rb#L98-L103
      BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/

      def valid_accept_header
        (xhr? && (accept.present? || content_mime_type)) ||
          (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS)
      end

解決

ということで、AngularJSのデフォルトAcceptヘッダから*/*を除外すればMIME Type判別が期待通りに動くようになる。

$httpProvider.defaults.headers.common["Accept"] = 'application/json';

もしくは、XHRのヘッダーを付与してもOK。
js
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';

15
16
0

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
15
16