$ Http (इंयू-राउटर) को $ http इंटरसेप्टर में इंजेक्ट करने से सर्कुलर निर्भरता हो जाती है


120

मैं क्या हासिल करने की कोशिश कर रहा हूं

$ Http अनुरोध 401 त्रुटि होने की स्थिति में मैं एक निश्चित स्थिति (लॉगिन) में संक्रमण करना चाहूंगा। इसलिए मैंने $ http इंटरसेप्टर बनाया है।

समस्या

जब मैं इंटरसेप्टर में '$ स्टेट' डालने की कोशिश कर रहा हूं तो मुझे एक परिपत्र निर्भरता मिलती है। मैं इसे क्यों और कैसे ठीक करूं?

कोड

//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);

कारण

कोणीय-यूआई-राउटर$http एक निर्भरता के रूप में सेवा को इंजेक्ट करता है $TemplateFactoryजिसमें इंटरसेप्टर को भेजने पर स्वयं के $httpभीतर एक परिपत्र संदर्भ बनाता है $httpProvider

यदि आप इस $httpतरह से एक इंटरसेप्टर में सीधे सेवा को इंजेक्ट करने का प्रयास करते हैं तो एक ही परिपत्र निर्भरता अपवाद को फेंक दिया जाएगा ।

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

चिंताओ का विभाजन

परिपत्र निर्भरता अपवाद यह संकेत कर सकते हैं कि आपके आवेदन के भीतर चिंताओं का मिश्रण है जो स्थिरता के मुद्दों का कारण बन सकता है। यदि आप खुद को इस अपवाद के साथ पाते हैं तो आपको अपने आर्किटेक्चर को देखने के लिए समय लेना चाहिए ताकि आप यह सुनिश्चित कर सकें कि आप किसी भी निर्भरता से बचें जो खुद को संदर्भित करता है।

@ स्टेफेन फ्रेडरिक का जवाब

मैं नीचे दिए गए जवाब से सहमत हूं कि $injectorवांछित सेवा का संदर्भ प्राप्त करने के लिए सीधे उपयोग करना आदर्श नहीं है और इसे एक विरोधी पैटर्न माना जा सकता है।

एक घटना का उत्सर्जन एक बहुत अधिक सुरुचिपूर्ण है और समाधान भी है।


1
यह कोणीय 1.3 के लिए कैसे समायोजित किया जाएगा, जहां इंटरसेप्टर में 4 अलग-अलग फ़ंक्शन पारित किए गए हैं?
मैकीज पगड़ी

3
उपयोग समान होगा, आप $injectorसेवा को अपने इंटरसेप्टर में इंजेक्ट करेंगे और कॉल करें $injector.get()जहां आपको $stateसेवा प्राप्त करने की आवश्यकता है ।
जोनाथन पालुम्बो

मुझे $ injectot.get ("$ state") मिलता है जैसा कि << परिभाषित नहीं है >>, क्या आप कृपया बता सकते हैं कि क्या समस्या हो सकती है?
संदीप काले

यह निश्चित रूप से एक जीवनरक्षक है जब यह एक साधारण स्थिति है, लेकिन जब आप इसमें भाग लेते हैं तो यह एक संकेत है कि आपने वास्तव में अपने कोड में कहीं एक परिपत्र निर्भरता बनाई है, जो कि अपने DI के साथ AngularJS में करना आसान है। मिसको हेवरी अपने ब्लॉग में इसे बहुत अच्छी तरह से समझाते हैं ; अत्यधिक अनुशंसा करते हैं कि आप अपने कोड को बेहतर बनाने के लिए इसे पढ़ें।
जद स्मिथ

2
$httpProvider.responseInterceptors.pushयदि आप कोणीय के बाद के संस्करणों का उपयोग कर रहे हैं तो अब और काम न करें। $httpProvider.interceptors.push()इसके बजाय उपयोग करें । आपको इसे भी संशोधित करना होगा interceptor। वैसे भी, अद्भुत उत्तर के लिए धन्यवाद! :)
श्याम

25

प्रश्न AngularJS की एक डुप्लिकेट है : एक HTTP इंटरसेप्टर (परिपत्र निर्भरता) में सेवा को इंजेक्ट करना

मैं उस धागे से अपना उत्तर यहां फिर से पोस्ट कर रहा हूं:

एक बेहतर तय

मुझे लगता है कि सीधे $ इंजेक्टर का उपयोग करना एक एंटीपैटर्न है।

परिपत्र निर्भरता को तोड़ने का एक तरीका एक घटना का उपयोग करना है: $ राज्य को इंजेक्ट करने के बजाय, $ rootScope को इंजेक्ट करें। सीधे पुनर्निर्देशित करने के बजाय, करें

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

प्लस

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

इस तरह आपने चिंताओं को अलग कर दिया है:

  1. 401 की प्रतिक्रिया का पता लगाएं
  2. लॉगिन करने के लिए पुनर्निर्देशित करें

2
दरअसल, वह प्रश्न इस प्रश्न का दोहराव है, क्योंकि यह प्रश्न उससे पहले पूछा गया था। हालांकि अपने सुरुचिपूर्ण तय प्यार, एक upvote है। ;-)
आरोन ग्रे

1
मैं इस बारे में भ्रमित कर रहा हूं कि इसे कहां रखा जाए। $ rootScope। $ Emit ("अनधिकृत");
एलेक्स

16

जोनाथन का समाधान तब तक बहुत अच्छा था जब तक मैंने वर्तमान स्थिति को बचाने की कोशिश नहीं की। में 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");
        }
    });

मैंने इस बारे में एक मुद्दा प्रस्तुत किया है ।
जस्टिन वर्बेल

मुझे लगता है कि यह ngResource से संभव नहीं है क्योंकि यह हमेशा अतुल्यकालिक है? मैं कुछ सामान की कोशिश की लेकिन मैं एक स्थिति परिवर्तन को रोकने के लिए संसाधन कॉल नहीं मिलता है ...
Bastian

4
क्या होगा यदि आप एक अनुरोध को रोकना चाहते हैं जो राज्य परिवर्तन को ट्रिगर नहीं करता है?
शिक्लोसि

आप उसी दृष्टिकोण का उपयोग कर सकते हैं जैसा @Stephen फ्रेडरिक ने ऊपर किया था, जो वास्तव में यह एक जैसा दिखता है, लेकिन एक कस्टम इवेंट का उपयोग करता है।
सईयाँकोडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.