この記事の参照元:https://my.oschina.net/ilivebox/blog/290881
序文:
今日、会社のプロジェクトでインターセプターに遭遇しました。名前が示すように、インターセプターは何かをインターセプトするためのものです。プロジェクトのインターセプターはすべてチームリーダーによってパッケージ化されており、理解できないので、DuNiangに尋ねました。と組み合わせオンラインの説明、ここに要約があります
インターセプターとは何ですか?
名前が示すように、インターセプターは何かをインターセプトすることです~~~
$ httpAngularJSの$ httpサービスにより、HTTPリクエストを送信することでバックグラウンドと通信できます。場合によっては、すべてのリクエストをキャプチャして、サーバーに送信する前に操作を実行したいことがあります。通話を完了する前に、応答をキャプチャして処理したい場合もあります。良い例は、グローバルhttp例外の処理です(当社のプロジェクトでは、応答をキャプチャし、グローバルhttp例外を処理し、後でコードを投稿します)。インターセプターが誕生しました。この記事では、AngularJSインターセプターを紹介し、いくつかの有用な例を示します。
$ httpProviderにはインターセプターの配列があり、いわゆるインターセプターは、配列に登録されている通常のサービスファクトリです。次の例は、インターセプターを作成する方法を示しています。
module.factory('myInterceptor',['$log',function($log){ // 就是一个服务
$log.debug('$log在这里向您展示这是一个常规的注入工厂');
var myInterceptor={};
...
...
return myInterceptor;
}])
次に、その名前を$ httpProvider.interceptors配列に追加します。
<!-- lang: js -->
module.config(['$httpProvider', function($httpProvider) { // config是配置服务的
$httpProvider.interceptors.push('myInterceptor');
}]);
インターセプターが実行できる操作とその機能は何ですか
requestメソッドを実装してリクエストをインターセプトします。このメソッドは、$ httpがリクエストをバックグラウンドに送信する前に実行されるため、構成を変更したり、他の操作を実行したりできます。このメソッドは、要求構成オブジェクト(要求構成オブジェクト)をパラメーターとして受け取り、構成オブジェクトまたはPromiseを返す必要があります。無効な構成オブジェクトまたはpromiseが返された場合、それは拒否され、$ http呼び出しが失敗します。
応答メソッドを実装して応答をインターセプトします。このメソッドは、$ httpがバックグラウンドから応答を受信した後に実行されるため、応答を変更したり、他の操作を実行したりできます。このメソッドは、応答オブジェクトをパラメーターとして受け取り、応答オブジェクトまたはpromiseを返す必要があります。応答オブジェクトには、要求構成、ヘッダー、ステータス、およびバックグラウンドからのデータが含まれます。無効な応答オブジェクトが返されるか、promiseが拒否されると、$ http呼び出しは失敗します。
requestErrorメソッドを実装してリクエストの例外をインターセプトする:リクエストの送信に失敗したり、インターセプターによって拒否されたりすることがあります。リクエスト例外インターセプターは、前のリクエストインターセプターによって中断されたリクエストをキャプチャします。リクエストを復元したり、プログレスバーを閉じたり、ボタンや入力ボックスをアクティブにしたりするなど、リクエストの前に行った設定を元に戻すために使用できます。
responseErrorメソッドを実装して応答例外をインターセプトします。バックグラウンド呼び出しが失敗することがあります。リクエストインターセプターによって拒否されたか、前のレスポンスインターセプターによって中断された可能性もあります。この場合、応答例外インターセプターは、バックグラウンド呼び出しを回復するのに役立ちます。
非同期操作(完全には理解されていません)
インターセプターで非同期操作を実行する必要がある場合があります。幸い、AngularJSを使用すると、遅延処理の約束を返すことができます。リクエストインターセプターでのリクエストの送信を遅らせるか、レスポンスインターセプターでの応答を遅らせます。
<!-- lang: js -->
module.factory('myInterceptor', ['$q', 'someAsyncService', function($q, someAsyncService) {
var requestInterceptor = {
request: function(config) {
var deferred = $q.defer(); // 创建一个异步对象;
someAsyncService.doAsyncOperation().then(function() {
// Asynchronous operation succeeded, modify config accordingly
...
deferred.resolve(config);
}, function() {
// Asynchronous operation failed, modify config accordingly
...
deferred.resolve(config);
});
return deferred.promise;
}
};
return requestInterceptor;
}]);
上記の例では、リクエストインターセプターは非同期操作を使用して、結果に基づいて構成を更新します。その後、更新された構成で操作を実行し続けます。延期が拒否された場合、httpリクエストは失敗します。
応答インターセプターの例は上記と同じです。
遅延が解析された場合にのみ、要求は成功したと見なされます。遅延が拒否された場合、要求は失敗します。
例
このセクションでは、AngularJSインターセプターの例をいくつか紹介します。これにより、AngularJSインターセプターの使用方法をよりよく理解し、それらがどのように役立つかを示すことができます。ただし、ここで提供するソリューションが必ずしも最良または最も正確なソリューションであるとは限らないことに注意してください。
###セッションの傍受、リクエストの傍受
サーバー認証を実現するには、2つの方法があります。1つ目は、従来のCookieベースの認証です。要求している各ユーザーは、サーバー側のCookieを介して認証されます。もう1つの方法は、トークンベースの認証です。ユーザーがログインすると、バックグラウンドからsessionTokenを取得します。sessionTokenはサーバー上の各ユーザーを識別し、サーバーに送信されるすべてのリクエストに含まれます。
次のsessionInjectorは、キャプチャされた各要求にx-session-tokenヘッダーを追加します(現在のユーザーがログインしている場合)。
<!-- lang: js -->
module.factory('sessionInjector', ['SessionService', function(SessionService) {
var sessionInjector = {
request: function(config) {
if (!SessionService.isAnonymus) {
config.headers['x-session-token'] = SessionService.token;
}
return config;
}
};
return sessionInjector;
}]);
module.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('sessionInjector'); //放到拦截器中
}]);
次に、リクエストを作成します
<!-- lang: js -->
$http.get('https://api.github.com/users/naorye/repos');
sessionInjectorによってインターセプトされる前の構成オブジェクトは次のようになります。
<!-- lang: js -->
{
"transformRequest": [
null
],
"transformResponse": [
null
],
"method": "GET",
"url": "https://api.github.com/users/naorye/repos",
"headers": {
"Accept": "application/json, text/plain, */*"
}
}
sessionInjectorによってインターセプトされた後の構成オブジェクトは、次のようになります。トークンがリクエストヘッダーに追加されます
<!-- lang: js -->
{
"transformRequest": [
null
],
"transformResponse": [
null
],
"method": "GET",
"url": "https://api.github.com/users/naorye/repos",
"headers": {
"Accept": "application/json, text/plain, */*",
"x-session-token": 415954427904
}
}
##タイムスタンプ(要求と応答のインターセプター)
インターセプターを使用して、バックグラウンドから応答を返すのにかかる時間を測定してみましょう。これは、各要求と応答にタイムスタンプを追加することで実行できます。
<!-- lang: js -->
module.factory('timestampMarker', [function() {
var timestampMarker = {
request: function(config) {
config.requestTimestamp = new Date().getTime();
return config;
},
response: function(response) {
response.config.responseTimestamp = new Date().getTime();
return response;
}
};
return timestampMarker;
}]);
module.config(['$httpProvider', function($httpProvider) { // 注册拦截器
$httpProvider.interceptors.push('timestampMarker');
}]);
上記で、要求と応答をインターセプトし、現在の時刻をconfig.requestTimestampとconfig.responseTimestampに割り当てます。
<!-- lang: js --> 调用接口看看从发送请求到响应需要多长时间
$http.get('https://api.github.com/users/naorye/repos').then(function(response) {
var time = response.config.responseTimestamp - response.config.requestTimestamp;
console.log('The request took ' + (time / 1000) + ' seconds.');
});
以下は、タイムスタンプの完全なコードです(要求と応答のインターセプター)
<!doctype html>
<html>
<head>
<title>Timestamp Marker Example</title>
<script src="../../angularjs/angular-1.5.8/angular.js"></script>
</head>
<body ng-app="timestamp-marker-example">
<div ng-controller="ExampleController">
The request took <span ng-bind="requestTime"></span> seconds.
</div>
<script type="text/javascript">
var module = angular.module('timestamp-marker-example', []);
module.factory('timestampMarker', [function() {
var timestampMarker = {
request: function(config) {
config.requestTimestamp = new Date().getTime();
return config;
},
response: function(response) {
response.config.responseTimestamp = new Date().getTime();
return response;
}
};
return timestampMarker;
}]);
module.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('timestampMarker');
}]);
module.controller('ExampleController', ['$scope', '$http', function($scope, $http) {
$scope.requestTime = '[waiting]';
$http.get('https://api.github.com/users/naorye/repos').then(function(response) {
var time = response.config.responseTimestamp - response.config.requestTimestamp;
$scope.requestTime = (time / 1000);
});
}]);
</script>
</body>
</html>
##リクエストリカバリ(リクエスト例外インターセプト)
リクエスト例外のインターセプトを示すために、前のインターセプターがリクエストを拒否した状況をシミュレートする必要があります。リクエスト例外インターセプターは、拒否の理由とリカバリリクエストを取得します。
requestRejectorとrequestRecovererの2つのインターセプターを作成しましょう。
<!-- lang: js -->
module.factory('requestRejector', ['$q', function($q) {
var requestRejector = {
request: function(config) {
return $q.reject('requestRejector');
}
};
return requestRejector;
}]);
module.factory('requestRecoverer', ['$q', function($q) {
var requestRecoverer = {
requestError: function(rejectReason) {
if (rejectReason === 'requestRejector') {
// Recover the request
return {
transformRequest: [],
transformResponse: [],
method: 'GET',
url: 'https://api.github.com/users/naorye/repos',
headers: {
Accept: 'application/json, text/plain, */*'
}
};
} else {
return $q.reject(rejectReason);
}
}
};
return requestRecoverer;
}]);
module.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('requestRejector');
// Removing 'requestRecoverer' will result to failed request
$httpProvider.interceptors.push('requestRecoverer');
}]);
次に、次のようにリクエストすると、requestRejectorがリクエストを拒否しましたが、ログに成功が表示されます。
<!-- lang: js -->
$http.get('https://api.github.com/users/naorye/repos').then(function() {
console.log('success');
}, function(rejectReason) {
console.log('failure');
});
完全なコード:http://www.webdeveasy.com/code/interceptors-in-angularjs-and-useful-examples/request-recover.html
##セッション回復(異常なインターセプターへの応答)
時々、私たちの単一ページのアプリケーションでは、セッションの損失が発生する可能性があります。この状況は、セッションの有効期限が切れているか、サーバーが異常であることが原因である可能性があります。セッションを復元するインターセプターを作成してから、元のリクエストを自動的に再送信しましょう(セッションの有効期限が切れていると仮定します)。
デモンストレーションの目的で、セッションが期限切れになり、httpステータスコード419が返されると仮定します。
<!-- lang: js -->
module.factory('sessionRecoverer', ['$q', '$injector', function($q, $injector) {
var sessionRecoverer = {
responseError: function(response) {
// Session has expired
if (response.status == 419){
var SessionService = $injector.get('SessionService');
var $http = $injector.get('$http'); // 获取注入
var deferred = $q.defer();
// Create a new session (recover the session)
// We use login method that logs the user in using the current credentials and
// returns a promise
SessionService.login().then(deferred.resolve, deferred.reject);
// When the session recovered, make the same backend call again and chain the request
return deferred.promise.then(function() {
return $http(response.config);
});
}
return $q.reject(response);
}
};
return sessionRecoverer;
}]);
module.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('sessionRecoverer');
}]);
このようにして、バックグラウンドコールが失敗し、セッションが期限切れになった場合、sessionRecovererは新しいセッションを作成してから、バックグラウンドを再度呼び出します。
総括する
この記事では、AngularJSインターセプターに関する知識を説明し、request、response、requestError、responseErrorインターセプターを紹介し、それらをいつどのように使用するかを説明しました。また、開発に使用できる実用的で便利な例をいくつか紹介します。
最後に、以下のプロジェクトで使用されるインターセプターを記述します
最初にインターセプターを作成します(appService.jsでは、後でプロジェクト構造の構成を作成するときに作成されます)。
//发送请求统一带上token
app.factory('authInterceptor', ["$rootScope", "$cookies", "$injector", "$q", "$location", function ($rootScope, $cookies, $injector, $q, $location) {
return {
request: function (config) {
config.headers = config.headers || {};
var headerName = 'Authorization';
var cookieName = 'XSRF-TOKEN';
//检查cookie是否存在
if ($cookies.get(cookieName) == undefined || $cookies.get(cookieName) == '') {
$location.path('/Index');
}
else {
config.headers[headerName] = 'Bearer ' + $cookies.get(cookieName);
}
//设置不缓存
config.headers["X-Requested-With"] = 'XMLHttpRequest';
config.headers["Cache-Control"] = "no-cache";
config.headers['Pragma'] = 'no-cache';
return config;
},
responseError: function (response) {
abp.ui.clearBusy("#mianBody");
abp.ui.clearBusy($('.modal-content'));//清除Modal遮罩层
//401服务端返回授权失败
if (response.status == 401) {
var msg = "您访问的接口未授权,请联系管理员";// response.data.error.message ||
abp.message.warn(msg, "提示");
} else if (response.status == 400) {
abp.message.warn("您输入的参数不符合规范,请重新核对", "提示");
} else if (response.status == 403) {
abp.message.warn("您没有接口访问权限,请联系管理员", "提示");
} else if (response.status == 500 && response.data.error.code == 200)//code为200需要提示到界面的错误信息
{
abp.message.warn(response.data.error.message, "提示");
}
else {
var errorData = "<div><p>" + response.status + ":" + response.statusText + "</p>" +
"<p>请求接口为:" + response.config.url + "</p>"
+ "</div>"
if (response.data.error && response.data.error.message) {
errorData += "<p>" + response.data.error.message + "<p>";
}
var topMenuId = $location.search().topMenuId;
$location.path("/error").search({ topMenuId: topMenuId, errorData: errorData });
return $q.reject(response);
}
//else
// if (response.status === 404) {
// $location.path('/Index');
// return $q.reject(response);
//}
},
response: function (response) {
return response;
}
};
}]);
インターセプターを使用
してapp.jsに書き込みます(app.jsはサービスを構成するために使用され、後でプロジェクトアーキテクチャ構成を作成するときに作成されます)。
app.config([
'$httpProvider',function($httpProvider){
$httpProvider.interceptors.push('authInterceptor');
}
])
このようにして、インターフェースは、要求の前、後、およびインターセプターでのグローバル例外処理の後に使用されます。効率を大幅に向上させます。