Как избежать компиляции $: ошибки tpload в ответе кода состояния 401
Мы разрабатываем одностраничное приложение с API-интерфейсом AngularJS и ASP.NET MVC Json Rest.
Когда неавторизованный клиент пытается перейти на частный маршрут (Ex:/Foo/Home/Template), чтобы получить шаблон, он получает ответ 401 от веб-API, и наше приложение AngularJS автоматически перенаправляет его на страницу входа в систему.
Мы обрабатываем 401 с $http перехватчиком с чем-то вроде этого:
if (response.status === 401) {
$location.path(routeToLogin);
return $q.reject(response);
}
Ввод правильных учетных данных позволяет клиенту получить шаблон.
Все работает отлично, за исключением одной детали; консоль Javascript сообщает об этой ошибке:
Error: [$compile:tpload] http://errors.angularjs.org/1.3.0/$compile/tpload?p0=%Foo%2FHome%2FTemplate%2F
Документация AngularJs гласит:
Описание
Эта ошибка возникает, когда компиляция $пытается получить шаблон из некоторого URL, и запрос не работает.
В нашем приложении AngularJs запрос выходит из строя, но он по дизайну, потому что ресурс есть, но к нему нельзя получить доступ (401).
Должен ли я двигаться дальше и принимать такую ошибку на консоли или можно ее отключить или экранировать?
EDIT:
Я немного отлаживал источник angular, и я нашел, какая часть кода создает исключение.
Поскольку мы используем TemplateUrl
для объявления наших шаблонов, мы косвенно используем функцию compileTemplateUrl
, которая выполняет этот вызов:
$templateRequest($sce.getTrustedResourceUrl(templateUrl))
это оставляет второй параметр (ignoreRequestError
) templateRequest
undefined.
ignoreRequestError (необязательно) boolean
Следует ли игнорировать исключение, когда запрос терпит неудачу, или шаблон пуст
Когда наш HTTP-перехватчик, обрабатывающий код статуса 401, отклоняет обещание, $http.get внутри $TemplateRequestProvider
выходит из строя и вызывает эту функцию:
function handleError() {
self.totalPendingRequests--;
if (!ignoreRequestError) {
throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
}
return $q.reject();
}
Я считаю, что мы не можем ничего сделать, чтобы предотвратить ошибку на консоли, поскольку TemplateUrl
не позволяет установить флаг ignoreRequestError
в значение false.
Я попытался обойти отклонение в случае кода состояния 401; это исправляет ошибку на консоли, но, к сожалению, она имеет побочный эффект: пустой шаблон неправильно кэшируется в TemplateCache
, вызывающий проблемы.
Ответы
Ответ 1
После некоторого размышления я вспомнил об украшении в Angular, он решил эту проблему отлично:
app.config(['$provide', function($provide) {
$provide.decorator('$templateRequest', ['$delegate', function($delegate) {
var fn = $delegate;
$delegate = function(tpl) {
for (var key in fn) {
$delegate[key] = fn[key];
}
return fn.apply(this, [tpl, true]);
};
return $delegate;
}]);
}]);
Ответ 2
Вы можете перехватить вызов шаблона по статусу и URL-адресу.
Plunker
app.config(function($httpProvider) {
var interceptor = function($location, $log, $q) {
function success(response) {
// The response if complete
$log.info(response);
return response;
}
function error(response) {
// The request if errors
$log.error(response);
return $q.reject(response);
}
return function(promise) {
return promise.then(success, error);
}
}
$httpProvider.responseInterceptors.push(interceptor);
});
Ответ 3
Как я вижу, у вас есть два варианта:
Вариант A)
пойти с перехватчиками. Однако, чтобы исключить компиляцию, вам нужно вернуть код статуса успеха внутри ошибки ответа (BAD) ИЛИ перенаправить на страницу входа в перехватчик (Хорошо):
app.factory('authInterceptorService', function () {
var interceptor = {};
interceptor.responseError = function (rejection) {
if (rejection.status === 401 && rejection.config.url === "home template url") {
//BAD IDEA
//console.log("faking home template");
//rejection.status = 200;
//rejection.data = "<h1>should log in to the application first</h1>";
//GOOD IDEA
window.location = "/login.html";
}
return rejection;
}
return interceptor;
});
и в app config:
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptorService');
}
Вариант b)
сделать домашний шаблон общедоступным. В конце концов, это должна быть просто наметка html, без какой-либо разумной информации.
это решение чистое... и, возможно, также возможно.