$ state (ui-router)를 $ http 인터셉터에 삽입하면 순환 종속성이 발생합니다.


120

내가 이루고자하는 것

$ http 요청이 401 오류를 반환하는 경우 특정 상태 (로그인)로 전환하고 싶습니다. 따라서 $ http 인터셉터를 만들었습니다.

문제

인터셉터에 '$ state'를 삽입하려고 할 때 순환 종속성이 발생합니다. 왜 그리고 어떻게 수정합니까?

암호

//Inside Config function

    var interceptor = ['$location', '$q', '$state', function($location, $q, $state) {
        function success(response) {
            return response;
        }

        function error(response) {

            if(response.status === 401) {
                $state.transitionTo('public.login');
                return $q.reject(response);
            }
            else {
                return $q.reject(response);
            }
        }

        return function(promise) {
            return promise.then(success, error);
        }
    }];

    $httpProvider.responseInterceptors.push(interceptor);

답변:


213

수정

$injector서비스를 사용하여 서비스에 대한 참조를 얻으십시오 $state.

var interceptor = ['$location', '$q', '$injector', function($location, $q, $injector) {
    function success(response) {
        return response;
    }

    function error(response) {

        if(response.status === 401) {
            $injector.get('$state').transitionTo('public.login');
            return $q.reject(response);
        }
        else {
            return $q.reject(response);
        }
    }

    return function(promise) {
        return promise.then(success, error);
    }
}];

$httpProvider.responseInterceptors.push(interceptor);

원인

angular-ui-router$http서비스를 종속성으로 주입 $TemplateFactory한 다음 $http내부에 대한 순환 참조를 생성 합니다.$httpProvider 는 인터셉터를 디스패치 할 자체 .

$http이와 같은 인터셉터에 서비스를 직접 주입하려고하면 동일한 순환 종속성 예외가 발생합니다 .

var interceptor = ['$location', '$q', '$http', function($location, $q, $http) {

우려 사항 분리

순환 종속성 예외는 애플리케이션 내에서 안정성 문제를 일으킬 수있는 우려 사항이 혼합되어 있음을 나타낼 수 있습니다. 이 예외가있는 경우 자신을 참조하는 종속성을 방지하기 위해 시간을내어 아키텍처를 살펴 봐야합니다.

@Stephen Friedrich의 대답

나는 아래의 답변에 동의합니다. $injector 하여 원하는 서비스에 대한 참조를 직접 얻는 것은 이상적이지 않으며 안티 패턴으로 간주 될 수 있다는 점에 .

이벤트를 내보내는 것은 훨씬 더 우아하고 분리 된 솔루션입니다.


1
인터셉터에 전달되는 4 개의 다른 함수가있는 Angular 1.3에서는 어떻게 조정 될까요?
마치에이 Gurban

3
사용법은 동일합니다. $injector서비스를 인터셉터에 주입하고 서비스를 $injector.get()받아야하는 곳을 호출 $state합니다.
Jonathan Palumbo

$ injectot.get ( "$ state")가 << 정의되지 않음 >>으로 표시됩니다. 문제가 무엇인지 말씀해 주시겠습니까?
sandeep kale 2015

이것은 간단한 상황 일 때는 확실히 생명의 은인이지만,이 문제에 부딪히면 실제로 코드 어딘가에 순환 종속성을 생성했다는 신호입니다. 이는 DI로 AngularJS에서 쉽게 수행 할 수 있습니다. Misko Hevery는 그의 블로그에서 그것을 아주 잘 설명합니다 . 코드를 개선하기 위해 읽어 보는 것이 좋습니다.
JD Smith

2
$httpProvider.responseInterceptors.pushAngular의 이후 버전을 사용하는 경우 더 이상 작동하지 않습니다. $httpProvider.interceptors.push()대신 사용하십시오 . 당신 interceptor은 또한 수정해야 할 것입니다. 어쨌든 멋진 답변 감사합니다! :)
shyam

25

질문은 AngularJS : HTTP 인터셉터에 서비스 주입 (순환 종속성) .

여기에 해당 스레드에서 내 답변을 다시 게시하고 있습니다.

더 나은 수정

$ injector를 직접 사용하는 것은 반 패턴이라고 생각합니다.

순환 종속성을 끊는 방법은 이벤트를 사용하는 것입니다. $ state를 주입하는 대신 $ rootScope를 주입하십시오. 직접 리디렉션하는 대신

this.$rootScope.$emit("unauthorized");

...을 더한

angular
    .module('foo')
    .run(function($rootScope, $state) {
        $rootScope.$on('unauthorized', () => {
            $state.transitionTo('login');
        });
    });

그런 식으로 우려 사항을 분리했습니다.

  1. 401 응답 감지
  2. 로그인으로 리디렉션

2
사실, 그 질문은이 질문의 중복입니다.이 질문은 그 질문이 있기 전에 질문 되었기 때문입니다. 그래도 우아한 수정을 사랑하므로 찬성 투표를하십시오. ;-)
Aaron Gray

1
this. $ rootScope. $ emit ( "unauthorized"); 어디에 넣을지 혼란 스럽습니다.
alex

16

현재 상태를 저장하려고 할 때까지 Jonathan의 솔루션은 훌륭했습니다. 에서 UI 라우터 v0.2.10 현재 상태는 인터셉터의 초기 페이지로드에 채워하지 않는 것 같습니다.

어쨌든 $ stateChangeError 이벤트를 대신 사용하여 해결했습니다 . $ stateChangeError의 이벤트는 모두 당신 제공 에서 국가뿐만 아니라 오류입니다. 꽤 멋져요.

$rootScope.$on('$stateChangeError',
    function(event, toState, toParams, fromState, fromParams, error){
        console.log('stateChangeError');
        console.log(toState, toParams, fromState, fromParams, error);

        if(error.status == 401){
            console.log("401 detected. Redirecting...");

            authService.deniedState = toState.name;
            $state.go("login");
        }
    });

이에 대한 문제 를 제출했습니다 .
Justin Wrobel 2014 년

항상 비동기이기 때문에 ngResource로는 불가능하다고 생각합니까? ... 나는 몇 가지 물건을 시도하지만 난 상태 변경을 방지하기 위해 자원 전화를하지 않는다
바스티안

4
상태 변경을 트리거하지 않는 요청을 가로 채려면 어떻게해야합니까?
Shikloshi

위에서 @Stephen Friedrich가했던 것과 동일한 접근 방식을 사용할 수 있습니다.이 접근 방식은 실제로 이와 유사하지만 사용자 지정 이벤트를 사용합니다.
saiyancoder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.