2015-02-20 11 views
15

पर बाध्यकारी खो देता है मैं एएमडी प्रारूप में ईएस 5 को पारदर्शी ट्रेलर के साथ ईएस 6 कक्षाओं का उपयोग करके बिल्डिंग और एंगुलरजेएस ऐप बना रहा हूं।angularjs http interceptor class (ES6) 'इस'

मेरी मॉड्यूल में

मैं इंटरसेप्टर वर्ग आयात और एक सेवा के रूप में यह रजिस्टर, और फिर module.config में $ httpProvider.interceptors के साथ इस सेवा रजिस्टर:

var commonModule = angular.module(moduleName, [constants.name]); 

import authenticationInterceptor from './authentication/authentication.interceptor'; 

commonModule.service('authenticationInterceptor', authenticationInterceptor); 

commonModule.config($httpProvider => { 
    $httpProvider.interceptors.push('authenticationInterceptor'); 
}); 

मेरे इंटरसेप्टर वर्ग दोनों $ q injects और $ विंडो सेवाएं, उन्हें बाद में उपयोग के लिए निर्माता में सहेजती है। मैं डीबगर के इस हिस्से का पालन किया और इंजेक्शन ठीक से हो रहा है:

'use strict'; 
/*jshint esnext: true */ 

var authenticationInterceptor = class AuthenticationInterceptor { 

    /* ngInject */ 
    constructor($q, $window) { 
     this.$q = $q; 
     this.$window = $window; 
    } 

    responseError(rejection) { 
     var authToken = rejection.config.headers.Authorization; 
     if (rejection.status === 401 && !authToken) { 
      let authentication_url = rejection.data.errors[0].data.authenticationUrl; 
      this.$window.location.replace(authentication_url); 
      return this.$q.defer(rejection); 
     } 
     return this.$q.reject(rejections); 
    } 
} 

authenticationInterceptor.$inject = ['$q', '$window']; 

export default authenticationInterceptor; 

जब मैं एक अनुरोध है कि एक इंटरसेप्टर उचित रूप से चलाता है के साथ प्रतिक्रिया करते हैं, लेकिन 'responseError' विधि 'इस' चर में विंडो ऑब्जेक्ट को इंगित करता है, न कि मेरे इंटरसेप्टर को, इसलिए मुझे तक पहुंच नहीं है। $ q या यह $ विंडो

मुझे पता नहीं लगा सकता क्यों? कोई विचार?

उत्तर

4
these lines of source code पर

देखो:

// apply interceptors 
forEach(reversedInterceptors, function(interceptor) { 
    if (interceptor.request || interceptor.requestError) { 
     chain.unshift(interceptor.request, interceptor.requestError); 
    } 
    if (interceptor.response || interceptor.responseError) { 
     chain.push(interceptor.response, interceptor.responseError); 
    } 
}); 

interceptor.responseError विधि श्रृंखला में धकेल दिया जाता है तो यह खो देता है उसके संदर्भ (सिर्फ समारोह धकेल दिया जाता है, किसी भी संदर्भ के बिना);

while (chain.length) { 
    var thenFn = chain.shift(); 
    var rejectFn = chain.shift(); 

    promise = promise.then(thenFn, rejectFn); 
} 

तो अगर वादा अस्वीकार कर दिया जाएगा, rejectFn (अपने responseError समारोह) एक साधारण समारोह के रूप में क्रियान्वित की जाएगी:

बाद here यह रूप में कॉलबैक अस्वीकार वादा में जोड़ दिया जाएगा। इस मामले में thiswindow के संदर्भ यदि स्क्रिप्ट को गैर-सख्त मोड में निष्पादित किया जा रहा है, या अन्यथा null के बराबर है।

आईएमएचओ कोणीय 1 ईएस 5 विचार के साथ लिखा गया था, इसलिए मुझे लगता है कि ईएस 6 के साथ इसका उपयोग करना एक अच्छा विचार नहीं है।

+1

कि व्यावहारिक प्रतिक्रिया के लिए धन्यवाद। मुझे कोणीय स्रोत कोड में खुदाई पसंद नहीं आया, यह बहुत घना है। ईएस 6 के लिए, यह ईएस 5 का एक सुपरसेट है, इस प्रकार मैं शैलियों को मिश्रित कर सकता हूं जहां अभी आवश्यक है, जो मैंने किया है। मैंने इंटरसेप्टर क्लास को एक ऐसे फ़ंक्शन में बदल दिया जो ऑब्जेक्ट देता है, बाकी सब कुछ वही था और यह काम करता था। मैं वक्र से आगे निकलने के लिए ES6 के लिए दबाव डाल रहा हूं, लेकिन कभी-कभी जब आप अपने दांतों में बग प्राप्त करते हैं :-) –

4

यह बिल्कुल वैसा ही समस्या मैं हो रही हैं, हालांकि, मैं सिर्फ es5 पर scoping मुद्दे को हल करना एक आत्म चर में 'इस' की स्थापना करके एक समाधान पाया, और यह ठीक काम करता है:

let self; 

class AuthInterceptor{ 

    constructor(session){ 
     self = this; 
     this.session = session; 
    } 

    request(config){ 
     if(self.session) { 
      config.headers = self.session.getSessionParams().headers; 
     } 
     return config; 
    } 

    responseError(rejection){ 
     if(rejection.status == 401){ 

     } 

     return rejection; 
    } 

} 

export default AuthInterceptor; 
+0

इस समाधान के साथ मेरी एक समस्या यह है कि आपका 'स्वयं' चर वैश्विक स्तर पर है। मुझे लगता है कि यदि आप एक एएमडी परिभाषित करते हैं तो इसे बंद करने में बाधा आती है, लेकिन यह अभी भी वैश्विक चर की तरह महसूस करती है। –

+0

मैंने कक्षा के अंदर इसे परिभाषित करने की कोशिश की, लेकिन यह काम नहीं करता है, मुझे नहीं पता कि एएस 6 कक्षा में स्थानीय चर को परिभाषित करने के लिए क्यों मना किया गया है, वैसे भी ट्रेसूर कंपाइलर सिस्टम.register मॉड्यूल परिभाषा – Avie

0

तीर कार्यों के साथ काम कर रहे समाधान:

var AuthInterceptor = ($q, $injector, $log) => { 
    'ngInject'; 

    var requestErrorCallback = request => { 
     if (request.status === 500) { 
      $log.debug('Something went wrong.'); 
     } 
     return $q.reject(request); 
    }; 

    var requestCallback = config => { 
     const token = localStorage.getItem('jwt'); 

     if (token) { 
      config.headers.Authorization = 'Bearer ' + token; 
     } 
     return config; 
    }; 

    var responseErrorCallback = response => { 
     // handle the case where the user is not authenticated 
     if (response.status === 401 || response.status === 403) { 
      // $rootScope.$broadcast('unauthenticated', response); 
      $injector.get('$state').go('login'); 
     } 
     return $q.reject(response); 
    } 

    return { 
    'request':  requestCallback, 
    'response':  config => config, 
    'requestError': requestErrorCallback, 
    'responseError': responseErrorCallback, 
    }; 
}; 

/***/ 
var config = function($httpProvider) { 
    $httpProvider.interceptors.push('authInterceptor'); 
}; 

/***/  
export 
default angular.module('services.auth', []) 
    .service('authInterceptor', AuthInterceptor) 
    .config(config) 
    .name; 
+0

ओपी के रूप में इसे लपेटता है एक कक्षा। आपका समाधान इसे एक समारोह या क्लासिक तरीके के रूप में करता है जो यह कोणीय 1 में किया जाता है, जो कि बुरा नहीं है। लेकिन यह सवाल का जवाब नहीं देता है। –

25

संदर्भ (this) खो दिया है क्योंकि कोणीय ढांचे केवल 0,123,255 के रूप में हैंडलर खुद को काम करता है के लिए संदर्भ रहता है, और उन्हें किसी भी संदर्भ के बिना सीधे invokes,ने बताया है।

मैंने हाल ही में टाइपस्क्रिप्ट का उपयोग करके $http इंटरसेप्टर्स लिखने के बारे में एक ब्लॉग पोस्ट लिखा है, जो ES6 कक्षाओं पर भी लागू होता है: AngularJS 1.x Interceptors Using TypeScript

संक्षेप में प्रस्तुत करना है कि मैं क्या के लिए अपने संचालकों में this खोना नहीं करने के लिए इस पोस्ट में चर्चा की है, आप के लिए, तीर कार्यों के रूप में तरीकों को परिभाषित करने के लिए प्रभावी ढंग से संकलित में वर्ग के constructor समारोह के अंदर सीधे कार्यों डाल होगा ईएस 5 कोड।

class AuthenticationInterceptor { 

    /* ngInject */ 
    constructor($q, $window) { 
     this.$q = $q; 
     this.$window = $window; 
    } 

    responseError = (rejection) => { 
     var authToken = rejection.config.headers.Authorization; 
     if (rejection.status === 401 && !authToken) { 
      let authentication_url = rejection.data.errors[0].data.authenticationUrl; 
      this.$window.location.replace(authentication_url); 
      return this.$q.defer(rejection); 
     } 
     return this.$q.reject(rejections); 
    } 
} 

आप वास्तव में जोर देते हैं, तो आपके इंटरसेप्टर एक पूरी तरह से प्रोटोटाइप आधारित वर्ग के रूप में लिखा होने पर, आप अपने इंटरसेप्टर के लिए एक आधार वर्ग को परिभाषित और यह विस्तार कर सकता है। आधार वर्ग उदाहरण के तरीकों के साथ प्रोटोटाइप इंटरसेप्टर कार्यों की जगह लेंगे, तो हम इस तरह हमारे इंटरसेप्टर लिख सकते हैं:

class HttpInterceptor { 
    constructor() { 
    ['request', 'requestError', 'response', 'responseError'] 
     .forEach((method) => { 
      if(this[method]) { 
      this[method] = this[method].bind(this); 
      } 
     }); 
    } 
} 

class AuthenticationInterceptor extends HttpInterceptor { 

    /* ngInject */ 
    constructor($q, $window) { 
     super(); 
     this.$q = $q; 
     this.$window = $window; 
    } 

    responseError(rejection) { 
     var authToken = rejection.config.headers.Authorization; 
     if (rejection.status === 401 && !authToken) { 
      let authentication_url = rejection.data.errors[0].data.authenticationUrl; 
      this.$window.location.replace(authentication_url); 
      return this.$q.defer(rejection); 
     } 
     return this.$q.reject(rejections); 
    } 
} 
+0

मेरे लिए काम किया। धन्यवाद। – iamrelos

0

तीर कार्यों के बारे में अन्य ललित जवाब compelement करने के लिए, मुझे लगता है कि यह थोड़ा क्लीनर एक स्थिर कारखाने विधि का उपयोग कर रहा है इंटरसेप्टर में:

export default class AuthenticationInterceptor { 
static $inject = ['$q', '$injector', '$rootRouter']; 
constructor ($q, $injector, $rootRouter) { 
    this.$q = $q; 
    this.$injector = $injector; 
    this.$rootRouter = $rootRouter; 
} 

static create($q, $injector, $rootRouter) { 
    return new AuthenticationInterceptor($q, $injector, $rootRouter); 
} 

responseError = (rejection) => { 
    const HANDLE_CODES = [401, 403]; 

    if (HANDLE_CODES.includes(rejection.status)) { 
    // lazy inject in order to avoid circular dependency for $http 
    this.$injector.get('authenticationService').clearPrincipal(); 
    this.$rootRouter.navigate(['Login']); 
    } 
    return this.$q.reject(rejection); 
} 
} 

उपयोग:

.config(['$provide', '$httpProvider', function ($provide, $httpProvider) { 
$provide.factory('reauthenticationInterceptor', AuthenticationInterceptor.create); 
$httpProvider.interceptors.push('reauthenticationInterceptor'); 
}]); 
4

बातचीत करने के लिए जोड़ने के लिए, आप एक वस्तु निर्माण से लौट सकते हैं टोर जिसमें स्पष्ट रूप से बाध्य वर्ग विधियां शामिल हैं।

export default class HttpInterceptor { 

    constructor($q, $injector) { 
     this.$q = $q; 
     this.$injector = $injector; 

     return { 
      request: this.request.bind(this), 
      requestError: this.requestError.bind(this), 
      response: this.response.bind(this), 
      responseError: this.responseError.bind(this) 
     } 
    } 

    request(req) { 
     this.otherMethod(); 
     // ... 
    } 

    requestError(err) { 
     // ... 
    } 

    response(res) { 
     // ... 
    } 

    responseError(err) { 
     // ... 
    } 

    otherMethod() { 
     // ... 
    } 

} 
+0

मुझे यह सबसे आसान/सबसे वाक्प्रचार समाधान मिला। मैंने फैक्ट्री ऑब्जेक्ट सृजन को कन्स्ट्रक्टर के बजाय एक बनाना() विधि में फेंक दिया। आपके टाइपो मैंने अंधेरे से कॉपी और चिपकाया वास्तव में मुझे एक लूप के लिए फेंक दिया, यद्यपि! प्रतिक्रिया: यह .responseError.bind (यह) ' – hackel

+0

धन्यवाद @ hackel - संपादित! – Jbird

1

ध्यान दें कि कक्षा गुणों में तीर फ़ंक्शंस का उपयोग ES7 के लिए एक प्रयोगात्मक विशेषता है। हालांकि अधिकांश ट्रांसलेटर को इसमें कोई समस्या नहीं है।

यदि आप आधिकारिक ES6 कार्यान्वयन से चिपकना चाहते हैं तो आप कन्स्ट्रक्टर में अपनी विधियों को परिभाषित करके प्रोटोटाइप विधियों के बजाय इंस्टेंस विधियां बना सकते हैं।

class AuthenticationInterceptor { 
 
    /* ngInject */ 
 
    constructor($q, $window) { 
 
    
 
    this.responseError = (rejection) => { 
 
     const authToken = rejection.config.headers.Authorization; 
 
     if (rejection.status === 401 && !authToken) { 
 
     const authentication_url = rejection.data.errors[0].data.authenticationUrl; 
 
     $window.location.replace(authentication_url); 
 
     return $q.defer(rejection); 
 
     } 
 
     return $q.reject(rejection); 
 
    }; 
 
    
 
    } 
 
}

मैं इस समाधान चाहते क्योंकि यह बॉयलरप्लेट कोड की मात्रा कम हो जाती है;

  • अब आपको अपनी सभी निर्भरताओं को this में रखना नहीं है। तो this.$q का उपयोग करने के बजाय आप केवल $q का उपयोग कर सकते हैं।
  • निर्माता

खरोज में से एक अतिरिक्त स्तर के बाद से स्पष्ट रूप से बाध्य वर्ग तरीकों वापस जाने के लिए कोई ज़रूरत नहीं एक नकारात्मक पक्ष यह है। इसके अलावा यह विधि उन वर्गों के लिए उपयुक्त नहीं हो सकती है जो बहुत तत्काल हैं क्योंकि यह उस मामले में अधिक स्मृति का उपभोग करता है। उदा .; प्रत्यक्ष वर्ग गुणों (प्रोटोटाइप विधियों के लिए पारदर्शी) का उपयोग करना उन घटकों के नियंत्रकों के लिए अधिक कुशल है जो एक पृष्ठ पर कई बार उपयोग किए जाने की संभावना है। सेवाओं, प्रदाताओं और कारखानों के बारे में चिंता न करें क्योंकि ये सभी सिंगलेट हैं और वे केवल एक बार तत्काल हो जाएंगे। ngInject

myInterceptor का उपयोग किए बिना

-1
export default class AuthInterceptor{ 


    /*@ngInject;*/ 
    constructor(SomeService,$q){ 

     this.$q=$q; 
     this.someSrv = SomeService; 



     this.request = (config) =>{ 
      ... 
      this.someSrv.doit(); 
      return config; 

     } 

     this.response = (response)=>{ 
      ... 
      this.someSrv.doit(); 
      return response; 
     } 

     this.responseError = (response) => { 
      ... 
      return this.$q.reject(response); 
     } 



    } 



} 
0

मेरे काम कर समाधान।js

export default ($q) => { 
let response = (res) => { 
    return res || $q.when(res); 
} 

let responseError = (rejection) => { 
    //do your stuff HERE!! 
    return $q.reject(rejection); 
} 

return { 
    response: response, 
    responseError: responseError 
} 

}

myAngularApp.js

// angular services 
import myInterceptor from 'myInterceptor'; 

// declare app 
const application = angular.module('myApp', []) 
     .factory('$myInterceptor', myInterceptor) 
     .config(['$httpProvider', function($httpProvider) { 
      $httpProvider.interceptors.push('$myInterceptor'); 
     }]);