$http
- 概要
- AngularJSの外から$httpを呼び出す
- $httpを使用したユニットテストの書き方
- ショートカット メソッド
- HTTPヘッダーの設定
- リクエストとレスポンスを変化させる
- キャッシュ
- インターセプター
- レスポンスインターセプター(非推奨)
- セキュリティに関する考慮事項
- 依存関係
- 使用方法
- delete(url, config)
- get(url, config)
- head(url, config)
- jsonp(url, config)
- post(url, data, config)
- put(url, data, config)
- defaults
- pendingRequests
- デモ
概要
$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構成オブジェクトが アクセスによって設定することが可能です。
これらのデフォルトに追加または上書きするには、単純にこれらの構成オブジェクトからプロパティの追加または削除を行います。
POSTまたはPUT以外のメソッドのヘッダーに追加するには、
単純に小文字のHTTPメソッド名のキーとして、新しいオブジェクトを追加します。
例:
$httpProvider.defaults.headers.get['My-Header']='value'
また、デフォルト値は同じ方法で$http.defaultsオブジェクト経由で、実行時に設定することができます。
リクエストとレスポンスを変化させる
リクエストとレスポンスの両方は、transform関数を使用することで変換することが可能です。 デフォルトで、Angularは下記の変換を適用します。
グローバル空間でデフォルトの変換(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種類の排除(拒絶?)インタセプターが存在します。)
// インターセプターをサービスとして登録
$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 |
型: 作成されたリクエストとそれがどのように処理されるべきかを記述したオブジェクトです。 オブジェクトは、下記のプロパティを持ちます。 |
戻り値 | 説明 |
型: 標準のthenメソッドと2つのHTTP固有のメソッドであるsuccessとerrorのある、 promiseオブジェクトを返します。 thenメソッドは、レスポンスオブジェクトと共に呼び出されるsuccessとerrorコールバックの2つの引数を受け取ります。 successとerrorメソッドは1つの引数を受け取る関数で、それぞれリクエスト成功時・失敗時に呼び出されます。 これらの関数に渡される引数は、thenメソッドに渡されたレスポンスオブジェクトの構造を崩したものです。(翻訳に自信なし) レスポンスオブジェクトは下記のプロパティを持ちます。 |
delete(url, config)
DELETEリクエストを実行するための略記メソッドです。
引数 | 説明 |
---|---|
url |
型: リクエスト先の相対、または絶対URLを指定します。 |
config(optional) |
型: 任意の構成オブジェクトを指定します。 |
戻り値 | 説明 |
型: Future object |
get(url, config)
GETリクエストを実行するための略記メソッドです。
引数 | 説明 |
---|---|
url |
型: リクエスト先の相対、または絶対URLを指定します。 |
config(optional) |
型: 任意の構成オブジェクトを指定します。 |
戻り値 | 説明 |
型: Future object |
head(url, config)
HEADリクエストを実行するための略記メソッドです。
引数 | 説明 |
---|---|
url |
型: リクエスト先の相対、または絶対URLを指定します。 |
config(optional) |
型: 任意の構成オブジェクトを指定します。 |
戻り値 | 説明 |
型: Future object |
jsonp(url, config)
JSONPリクエストを実行するための略記メソッドです。
引数 | 説明 |
---|---|
url |
型: リクエスト先の相対、または絶対URLを指定します。 JSON_CALLBACK文字列を含める必要があります。 |
config(optional) |
型: 任意の構成オブジェクトを指定します。 |
戻り値 | 説明 |
型: Future object |
post(url, data, config)
POSTリクエストを実行するための略記メソッドです。
引数 | 説明 |
---|---|
url |
型: リクエスト先の相対、または絶対URLを指定します。 |
data |
型: リクエストする内容を指定します。 |
config(optional) |
型: 任意の構成オブジェクトを指定します。 |
戻り値 | 説明 |
型: Future object |
put(url, data, config)
PUTリクエストを実行するための略記メソッドです。
引数 | 説明 |
---|---|
url |
型: リクエスト先の相対、または絶対URLを指定します。 |
data |
型: リクエストする内容を指定します。 |
config(optional) |
型: 任意の構成オブジェクトを指定します。 |
戻り値 | 説明 |
型: 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>
© 2017 Google
Licensed under the Creative Commons Attribution License 3.0.
このページは、ページトップのリンク先のAngularJS公式ドキュメント内のページを翻訳した内容を基に構成されています。 下記の項目を確認し、必要に応じて公式のドキュメントをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。
- AngularJSの更新頻度が高いため、元のコンテンツと比べてドキュメントの情報が古くなっている可能性があります。
- "訳注:"などの断わりを入れた上で、日本人向けの情報やより分かり易くするための追記を行っている事があります。