如何避免401状态代码响应上的$compile:tpload错误

How to avoid $compile:tpload errors on 401 status code response

本文关键字:compile tpload 错误 何避免 状态 代码 响应      更新时间:2023-09-26

我们正在使用AngularJS和ASP.NET MVC Json Rest API开发单页应用程序。

当未经验证的客户端尝试导航到专用路由(例如:/Foo/Home/Template)以获取模板时,它会从Web API获得401响应,我们的AngularJS应用程序会自动将其重定向到登录页面。

我们正在处理带有$http的401拦截器,其内容如下:

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的文件说明:

描述

当$compile尝试从URL,请求失败。

在我们的AngularJs应用程序中,请求失败,但这是设计的,因为资源在那里,但无法访问(401)。

我应该继续接受控制台上的这种错误吗?还是可以以某种方式将其静音或屏蔽?

编辑:

我对角度源进行了一点调试,发现代码的哪一部分引发了异常
由于我们使用TemplateUrl来声明我们的模板,因此我们间接地使用了进行以下调用的函数compileTemplateUrl

$templateRequest($sce.getTrustedResourceUrl(templateUrl))

这使得CCD_ 4的第二参数(ignoreRequestError)未被定义。

ignoreRequestError(可选)布尔值

当请求失败或模板为空

当我们的http拦截器(处理401状态代码)拒绝promise时,$TemplateRequestProvider中的$http.get失败并调用以下函数:

 function handleError() {
        self.totalPendingRequests--;
        if (!ignoreRequestError) {
          throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
        }
        return $q.reject();
      }

我相信我们无法阻止控制台上的错误,因为TemplateUrl不允许将ignoreRequestError标志设置为false。

在401状态码的情况下,我试图绕过拒绝;这修复了控制台上的错误,但遗憾的是,它有一个副作用:一个空模板被错误地缓存到TemplateCache中,导致其他问题。

经过思考,我想起了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;
  }]);
}]);

您应该能够通过状态和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);
});

在我看来,您有两个选项:

选项A)

去拦截。然而,为了消除编译,您需要在响应错误(BAD)内返回成功状态代码,或者重定向到拦截器内的登录页面(Good):

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(['$httpProvider', function ($httpProvider) {
   $httpProvider.interceptors.push('authInterceptorService');
}

选项b)

将主模板公开。毕竟,它应该只是html标记,没有任何合理的信息。

这个解决方案是干净的。。。也许也是可能的。