$http

概要

$httpサービスは、Angularサービスの中でも核となる機能で、 ブラウザのXMLHttpRequestオブジェクト、またはJSONPを通じてリモートHTTPサーバーと通信する機能です。

$httpサービスを使ったユニットテストについては、$httpBackendモックを参照してください。

高階層での抽象化のため、 $resourceサービスを確認してください。

$httpのAPIは、$qサービスによって晒されるdeferred/promiseのAPIに基づいています。 シンプルな形式での使用であれば、これは重要なことではありませんが、 高度な使用をするのであれば、これらのAPIとそのAPIが保証してくれることへの理解が重要になります。

一般的な使用

$httpサービスは、1つの引数を取る関数です。 その引数は設定オブジェクトで、HTTPリクエストを作るのに使用され、 2つの$httpが指定したメソッドであるsuccessとerrorのpromiseを返します。

$http({method: 'GET', url: '/someUrl'}).
  success(function(data, status, headers, config) {
    // レスポンスが有効の場合に、非同期で呼び出されるコールバックです。
  }).
  error(function(data, status, headers, config) {
    // エラーが発生、またはサーバからエラーステータスが返された場合に、
    // 非同期で呼び出されます。
  });

$http関数呼び出しで返される値がpromiseのため、 コールバックの登録にそのメソッドを使用することも可能で、 これらのコールバックは、レスポンスを表すオブジェクトを唯一の引数として受け取ります。 詳細については以下のAPIの情報を参照してください。

レスポンスのステータスコード200番台は成功ステータスで、その結果successコールバックが呼び出されます。 レスポンスがリダイレクトの場合、XMLHttpRequestはそれに従うため、errorコールバックがそのようなレスポンスでは呼び出されないことに注意してください。

AngularJSの外から$httpを呼び出す

$httpサービスは、実際には次の$digest()が実行されるまでリクエストを送信しません。 ほとんどのケースで$httpは、$apply()ブロックから呼ばれるので、通常これは問題になりません。 もし、$httpをAngularの範囲外から呼び出す場合、$applyの呼び出し内にラップして$digestを発生させるべきです。 また、エラーもこのブロック内で正しく扱うべきです。

$scope.$apply(function() {
  $http(...);
});

$httpを使用したユニットテストの書き方

ユニットテストを行う際は、大抵の場合は開発者が$digestサイクルについて意識しておく必要があります。 もし、$httpBackend.flush()呼び出し前に$digestをトリガーしていないと、 リクエストは作られず、$httpBackend.expect(...)は失敗します。 この解決策は、前述したように$httpメソッドを$applyブロック内で実行することです。 When unit testing you are mostly responsible for scheduling the $digest cycle. If you do not trigger a $digest before calling $httpBackend.flush() then the request will not have been made and $httpBackend.expect(...) expectations will fail. The solution is to run the code that calls the $http() method inside a $apply block as explained in the previous section.

$httpBackend.expectGET(...);
$scope.$apply(function() {
  $http.get(...);
});
$httpBackend.flush();

ショートカット メソッド

$httpサービスのすべての呼び出しは、HTTPメソッドとURLを渡す必要があり、   また、POST/PUTは加えてリクエストを行うデータを必要とします。 これらのリクエストに合わせたショートカット メソッドが用意されています。

$http.get('/someUrl').success(successCallback);
$http.post('/someUrl', data).success(successCallback);

下記は全てのショートカットメソッドの一覧になります。

  • $http.get
  • $http.head
  • $http.post
  • $http.put
  • $http.delete
  • $http.jsonp

HTTPヘッダーの設定

$httpサービスは、全てのリクエストにHTTPヘッダーを自動的に追加します。 これらのデフォルトは、現在のデフォルト設定が含まれている$httpProvider.defaults.headers構成オブジェクトが アクセスによって設定することが可能です。

$httpProvider.defaults.headers.common(全てのリクエストで共通):
Accept: application/json, text/plain, * / *
$httpProvider.defaults.headers.post: (POSTリクエスト用)
Content-Type: application/json
$httpProvider.defaults.headers.put (PUTリクエスト用)
Content-Type: application/json

これらのデフォルトに追加または上書きするには、単純にこれらの構成オブジェクトからプロパティの追加または削除を行います。 POSTまたはPUT以外のメソッドのヘッダーに追加するには、 単純に小文字のHTTPメソッド名のキーとして、新しいオブジェクトを追加します。
例:

$httpProvider.defaults.headers.get['My-Header']='value'

また、デフォルト値は同じ方法で$http.defaultsオブジェクト経由で、実行時に設定することができます。

リクエストとレスポンスを変化させる

リクエストとレスポンスの両方は、transform関数を使用することで変換することが可能です。 デフォルトで、Angularは下記の変換を適用します。

リクエストの変換(transform):
  • リクエスト構成オブジェクトのdataプロパティに、オブジェクトが含まれる場合はJSON形式にシリアライズします。
レスポンスの変換(transform):
もし、XSRFプレフィックスが見つかった場合、それを除去します。(詳しくは、後述する「セキュリティに関する考慮事項を」を確認してください。) もし、JSONレスポンスが見つかった場合、JSONパーサーを使ってシリアライズを元に戻します。

グローバル空間でデフォルトの変換(transform)の追加・上書きをするには、 $httpProvider.defaults.transformRequest$httpProvider.defaults.transformResponseを修正します。 これらのプロパティは、デフォルトで変換(transform)関数の配列になっていて、 新しい変換(transform)関数を、変換チェイン内に追加(push)したり、または除去(unshift)することが可能になっています。 また、配列で囲わずに、これらのプロパティへの変換関数を直接割り当てることにより、 任意のデフォルトの変換を完全に上書きすることができます。

ローカルのリクエスト/レスポンス変換の上書きも同様で、 $httpに渡された構成オブジェクトのプロパティ、transformRequest、transformResponseを変更します。

キャッシュ

キャッシュを有効にするには、構成プロパティcacheをtrueに設定します。 キャッシュが有効の場合、$httpはサーバからのレスポンスをローカルキャッシュに格納します。 次のレスポンスは、サーバへのリクエストを行わずにキャッシュから提供されます。

キャッシュからレスポンスが返される場合でも、実際のリクエストと同様に非同期でデータ通信が行われることに注意してください。

$cacheFactoryで構築されたカスタムのデフォルトキャッシュは、 $http.defaults.cache内で提供可能になります。 これをスキップするには、構成プロパティのcacheをfalseに設定します。

インターセプター

インターセプター(傍受)を作り始める前に、 $qとdeferred/promiseのAPIを理解しておきましょう。

グローバルのエラー処理、認証、またはあらゆる種類の同期または非同期の、リクエストの前処理、またはレスポンスの後処理のために、 サーバに引き渡される前にリクエストを、そして、これらのリクエストを行ったアプリケーションコードに引き渡される前にレスポンスを、 それぞれ傍受できることが望ましいでしょう。 インターセプターは、この同期および非同期の前処理の必要性を満たすために、 promise APIを活用します。

インターセプターは、$httpProvider.interceptors配列に追加されることによって、 $httpProviderに登録されたサービスファクトリーです。 ファクトリーは呼び出されると、(指定されれば)依存関係を注入し、インターセプターを返します。

インターセプターは、2種類存在します。(また、2種類の排除(拒絶?)インタセプターが存在します。)

request:
requestインターセプターは、http設定オブジェクトで呼び出されます。 この関数は、自由に設定を変更することも、また新しく設定を作成することも可能です。 この関数は直接、またはpromiseとして設定を返す必要があります。
requestError:
requestErrorインターセプターは、1つ前のインターセプターがエラーをスローするか、 拒否として処理された際に呼び出されます。
response:
responseインターセプターは、httpのresponseオブジェクトで呼び出されます。 この関数は、自由に設定を変更することも、また新しく設定を作成することも可能です。 この関数は直接、またはpromiseとしてresponseを返す必要があります。
responseError:
responseErrorインターセプターは、1つ前のインターセプターがエラーをスローするか、 拒否として処理された際に呼び出されます。
// インターセプターをサービスとして登録
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
  return {
    // 任意のメソッド
    'request': function(config) {
      // 成功時に行うこと
      return config || $q.when(config);
    },

    // 任意のメソッド
   'requestError': function(rejection) {
      // エラー時に行うこと
      if (canRecover(rejection)) {
        return responseOrNewPromise
      }
      return $q.reject(rejection);
    },



    // 任意のメソッド
    'response': function(response) {
      // 成功時に行うこと
      return response || $q.when(response);
    },

    // 任意のメソッド
   'responseError': function(rejection) {
      // エラー時に行うこと
      if (canRecover(rejection)) {
        return responseOrNewPromise
      }
      return $q.reject(rejection);
    };
  }
});

$httpProvider.interceptors.push('myHttpInterceptor');



// 匿名関数経由で、インターセプターを登録
$httpProvider.interceptors.push(function($q, dependency1, dependency2) {
  return {
   'request': function(config) {
       // 上記と同じ
    },
    'response': function(response) {
       // 上記と同じ
    }
});

レスポンスインターセプター(非推奨)

インターセプター(傍受)を作り始める前に、 $qとdeferred/promiseのAPIを理解しておきましょう。

認証、同期の類、または非同期の事前処理によるレスポンス受け取りのグローバルのエラーハンドリングの用途で、 リクエストが開始されるアプリケーションコードを扱う前に、HTTPリクエストのためにレスポンスをインターセプト出来ることが望まれます。 レスポンスのインターセプトは、 promise API全体に、 これを必要とする同期、非同期の事前処理に影響します。

インターセプターは、$httpProvider.responseInterceptors配列に追加されることによって、 登録されるサービスのファクトリーです。 ファクトリーは呼び出されると依存関係を使用(指定されていれば)して注入され、 インターセプターを返します。 インターセプターは関数でpromiseを取得して、元のまたは新しいpromiseを返します。

// サービスとしてインターセプターを登録
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
  return function(promise) {
    return promise.then(function(response) {
      // 成功時に行うこと
      return response;
    }, function(response) {
      // エラー時に行うこと
      if (canRecover(response)) {
        return responseOrNewPromise
      }
      return $q.reject(response);
    });
  }
});

$httpProvider.responseInterceptors.push('myHttpInterceptor');


// 匿名関数経由で、インターセプターを登録
$httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
  return function(promise) {
    // 上記と同じ
  }
});

セキュリティに関する考慮事項

Webアプリケーション設計時には、下記のセキュリティの脅威を意識する必要があります。

サーバとクライアントの両方で協同して、これらの脅威を取り除かなければいけません。 Angularは、これらの問題に対処するための方策が事前に構成されていますが、 バックエンドサーバとの連携が不可欠になります。

JSON脆弱性に対する防御

JSONの脆弱性Anatomy of a Subtle JSON Vulnerabilityは、 ある条件下で、あなたのJSONリソースのURLへのJSONPリクエストを第三者のウェブサイトに許可してしまいます。 これに対抗するために、全てのJSONリクエストの接頭辞として")]}',\n"の文字列を付けます。 AngularはJSONとして処理する前に、自動的にこの接頭辞を取り除いてくれます。

例えば、もしあなたのサーバが下記が返ることを必要とする場合、

['one','two']

とすると、攻撃に対して脆弱であるため、次のようにして返します。

)]}',
['one','two']

Angularは、JSONとして処理が行われる前に接頭辞を取り除いてくれます。

クロスサイト・リクエストフォージェリ(XSRF)への防御

(訳注:日本では、クロスサイト・リクエストフォージェリは、「CSRF」と略されることが多いようですが、どちらも略記として使用されます) XSRFは、非認証のサイトがユーザーのプライベートデータを取得する事が出来てしまう手法です。 AngularはXSRFに対抗するメカニズムを提供します。 XHRリクエストが実行された際に、$httpサービスはCookieからトークン(デフォルトでは、XSRF-TOKEN)を読み取り、 HTTPヘッダーにセットします。(X-XSRF-TOKEN) 自分のドメイン上で実行されるJavaScriptのみCookieを読み込むことが出来るので、 サーバーはXHRが、自分のドメイン上で実行されて送られてきた事を保証することが出来ます。 ヘッダーはクロスドメインのリクエストを設定しません。

依存関係

  • $httpBackend
  • $browser
  • $cacheFactory
  • $rootScope
  • $q
  • $injector

使用方法

$http(config);
引数 説明
config

型:object

作成されたリクエストとそれがどのように処理されるべきかを記述したオブジェクトです。 オブジェクトは、下記のプロパティを持ちます。

method – {string}
HTTPメソッドを指定します。(例:'GET'、'POST'等)
url – {string}
リクエストする絶対または相対URLを指定します。
params – {Object.<string|Object>}
文字列またはオブジェクトのマップを指定し、URLの後ろに?key1=value1&key2=value2のように変更されて付け加えられます。 もし、値が文字列で無ければ、JSON式に変更されます。
data – {string|Object}
リクエストのメッセージ(ボディ)のデータとして送信されます。
headers – {Object}
文字列または、サーバーへ送信するリクエストHTTPヘッダーの文字列を返す関数のマップを指定します。 もし関数がnullを返した場合、そのヘッダーは送信されません。
xsrfHeaderName – {string}
XSRFトークンで移入するHTTPヘッダーの名前を指定します。
xsrfCookieName – {string}
XSRFトークンを含むCookieの名前を指定します。
transformRequest – {function(data, headersGetter)|Array.<function(data, headersGetter)>}
変形関数、またはそのような関数の配列を指定します。 変形関数は、HTTPリクエストのボディとヘッダーを受け取り、 それを変形したバージョン(通常、リアライズ化される)のものを返します。
transformResponse – {function(data, headersGetter)|Array.<function(data, headersGetter)>}
変形関数、またはそのような関数の配列を指定します。 変形関数は、HTTPレスポンスのボディとヘッダーを受け取り、 それを変形したバージョン(通常、シリアライズ化を戻す)のものを返します。
cache – {boolean|Cache}
もし、trueが指定された場合、デフォルトの$httpキャッシュがGETリクエストをキャッシュするのに使用されますが、 そうでなければ、キャッシュのインスタンスが$cacheFactoryで作成されていれば、 そのキャシュが使用されます。
timeout – {number|Promise}
タイムアウトされるミリ秒、またはresolveされた際にリクエストを中断すべきpromiseを指定します。
withCredentials - {boolean}
XHRオブジェクトにwithCredentialsフラグを設定するか否かを指定します。 詳細は、証明書付きリクエストを参照してください。
responseType - {string}
詳細は、requestTypeを参照してください。
戻り値 説明
 

型:HttpPromise

標準のthenメソッドと2つのHTTP固有のメソッドであるsuccessとerrorのある、 promiseオブジェクトを返します。 thenメソッドは、レスポンスオブジェクトと共に呼び出されるsuccessとerrorコールバックの2つの引数を受け取ります。 successとerrorメソッドは1つの引数を受け取る関数で、それぞれリクエスト成功時・失敗時に呼び出されます。 これらの関数に渡される引数は、thenメソッドに渡されたレスポンスオブジェクトの構造を崩したものです。(翻訳に自信なし) レスポンスオブジェクトは下記のプロパティを持ちます。

data – {string|Object}
変形関数を使用して、変形されたレスポンス・ボディです。
status – {number}
レスポンスのHTTPステータスコードです。
headers – {function([headerName])}
ヘッダーを取得する関数です。
config – {Object}
リクエストを作成するのに使用された構成オブジェクトです。

delete(url, config)

DELETEリクエストを実行するための略記メソッドです。

引数 説明
url

型:string

リクエスト先の相対、または絶対URLを指定します。

config(optional)

型:Object

任意の構成オブジェクトを指定します。

戻り値 説明
 

型:HttpPromise

Future object

get(url, config)

GETリクエストを実行するための略記メソッドです。

引数 説明
url

型:string

リクエスト先の相対、または絶対URLを指定します。

config(optional)

型:Object

任意の構成オブジェクトを指定します。

戻り値 説明
 

型:HttpPromise

Future object

head(url, config)

HEADリクエストを実行するための略記メソッドです。

引数 説明
url

型:string

リクエスト先の相対、または絶対URLを指定します。

config(optional)

型:Object

任意の構成オブジェクトを指定します。

戻り値 説明
 

型:HttpPromise

Future object

jsonp(url, config)

JSONPリクエストを実行するための略記メソッドです。

引数 説明
url

型:string

リクエスト先の相対、または絶対URLを指定します。 JSON_CALLBACK文字列を含める必要があります。

config(optional)

型:Object

任意の構成オブジェクトを指定します。

戻り値 説明
 

型:HttpPromise

Future object

post(url, data, config)

POSTリクエストを実行するための略記メソッドです。

引数 説明
url

型:string

リクエスト先の相対、または絶対URLを指定します。

data

型:*

リクエストする内容を指定します。

config(optional)

型:Object

任意の構成オブジェクトを指定します。

戻り値 説明
 

型:HttpPromise

Future object

put(url, data, config)

PUTリクエストを実行するための略記メソッドです。

引数 説明
url

型:string

リクエスト先の相対、または絶対URLを指定します。

data

型:*

リクエストする内容を指定します。

config(optional)

型:Object

任意の構成オブジェクトを指定します。

戻り値 説明
 

型:HttpPromise

Future object

defaults

$httpProvider.defaultsのランタイムと同等です。 リクエストとレスポンスの変更はもちろんの事、withCredentialsなどのデフォルトのヘッダーの設定を行うことが可能です。

このページで前述した"HTTPヘッダーの設定"と"リクエストとレスポンスを変化させる"の項目を参照してください。

pendingRequests

現在、待ち状態になっているリクエストのための設定オブジェクトの配列です。 これは主にデバッグの用途で使用されるものです。

デモ

<!doctype html>
<html ng-app>
  <head>
    <script src="http://code.angularjs.org/1.2.0-rc.3/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="FetchCtrl">
      <select ng-model="method">
        <option>GET</option>
        <option>JSONP</option>
      </select>
      <input type="text" ng-model="url" size="80"/>
      <button ng-click="fetch()">fetch</button><br>
      <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
      <button
        ng-click="updateModel('JSONP',
                      'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
        Sample JSONP
      </button>
      <button
        ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
          Invalid JSONP
        </button>
      <pre>http status code: {{status}}</pre>
      <pre>http response data: {{data}}</pre>
    </div>
  </body>
</html>
Hello, $http!
function FetchCtrl($scope, $http, $templateCache) {
  $scope.method = 'GET';
  $scope.url = 'http-hello.html';

  $scope.fetch = function() {
    $scope.code = null;
    $scope.response = null;

    $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
      success(function(data, status) {
        $scope.status = status;
        $scope.data = data;
      }).
      error(function(data, status) {
        $scope.data = data || "Request failed";
        $scope.status = status;
    });
  };

  $scope.updateModel = function(method, url) {
    $scope.method = method;
    $scope.url = url;
  };
}
it('should make an xhr GET request', function() {
  element(':button:contains("Sample GET")').click();
  element(':button:contains("fetch")').click();
  expect(binding('status')).toBe('200');
  expect(binding('data')).toMatch(/Hello, $http!/);
});

it('should make a JSONP request to angularjs.org', function() {
  element(':button:contains("Sample JSONP")').click();
  element(':button:contains("fetch")').click();
  expect(binding('status')).toBe('200');
  expect(binding('data')).toMatch(/Super Hero!/);
});

it('should make JSONP request to invalid URL and invoke the error handler',
    function() {
  element(':button:contains("Invalid JSONP")').click();
  element(':button:contains("fetch")').click();
  expect(binding('status')).toBe('0');
  expect(binding('data')).toBe('Request failed');
});
<!doctype html>
<html ng-app>
  <head>
    <script src="http://code.angularjs.org/1.2.0-rc.3/angular.min.js"></script>
<script>function FetchCtrl($scope, $http, $templateCache) {
  $scope.method = 'GET';
  $scope.url = 'http-hello.html';

  $scope.fetch = function() {
    $scope.code = null;
    $scope.response = null;

    $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
      success(function(data, status) {
        $scope.status = status;
        $scope.data = data;
      }).
      error(function(data, status) {
        $scope.data = data || "Request failed";
        $scope.status = status;
    });
  };

  $scope.updateModel = function(method, url) {
    $scope.method = method;
    $scope.url = url;
  };
}
</script>
  </head>
  <body>
    <div ng-controller="FetchCtrl">
      <select ng-model="method">
        <option>GET</option>
        <option>JSONP</option>
      </select>
      <input type="text" ng-model="url" size="80"/>
      <button ng-click="fetch()">fetch</button><br>
      <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
      <button
        ng-click="updateModel('JSONP',
                      'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
        Sample JSONP
      </button>
      <button
        ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
          Invalid JSONP
        </button>
      <pre>http status code: {{status}}</pre>
      <pre>http response data: {{data}}</pre>
    </div>
  </body>
</html>

 Back to top

© 2017 Google
Licensed under the Creative Commons Attribution License 3.0.

このページは、ページトップのリンク先のAngularJS公式ドキュメント内のページを翻訳した内容を基に構成されています。 下記の項目を確認し、必要に応じて公式のドキュメントをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。

  • AngularJSの更新頻度が高いため、元のコンテンツと比べてドキュメントの情報が古くなっている可能性があります。
  • "訳注:"などの断わりを入れた上で、日本人向けの情報やより分かり易くするための追記を行っている事があります。