কৌণিক জেএস: এইচটিটিপি ইন্টারসেপ্টারে ইনজেকশন পরিষেবা (বিজ্ঞপ্তি নির্ভরতা)


118

প্রমাণীকরণ হ্যান্ডেল করার জন্য আমি আমার AngularJS অ্যাপ্লিকেশনটির জন্য একটি HTTP ইন্টারসেপ্টর লেখার চেষ্টা করছি।

এই কোডটি কাজ করে, তবে আমি নিজে থেকেই কোনও পরিষেবা ইনজেকশনের বিষয়ে উদ্বিগ্ন যেহেতু আমি ভেবেছিলাম যে কৌনিকটি স্বয়ংক্রিয়ভাবে এটি পরিচালনা করবে:

    app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.interceptors.push(function ($location, $injector) {
        return {
            'request': function (config) {
                //injected manually to get around circular dependency problem.
                var AuthService = $injector.get('AuthService');
                console.log(AuthService);
                console.log('in request interceptor');
                if (!AuthService.isAuthenticated() && $location.path != '/login') {
                    console.log('user is not logged in.');
                    $location.path('/login');
                }
                return config;
            }
        };
    })
}]);

আমি যা করতে শুরু করেছিলাম তা কিন্তু বিজ্ঞপ্তি নির্ভরতা সমস্যার মধ্যে পড়ে:

    app.config(function ($provide, $httpProvider) {
    $provide.factory('HttpInterceptor', function ($q, $location, AuthService) {
        return {
            'request': function (config) {
                console.log('in request interceptor.');
                if (!AuthService.isAuthenticated() && $location.path != '/login') {
                    console.log('user is not logged in.');
                    $location.path('/login');
                }
                return config;
            }
        };
    });

    $httpProvider.interceptors.push('HttpInterceptor');
});

আমার উদ্বেগ হওয়ার আরেকটি কারণ হ'ল কৌণিক ডক্সের $ http এর বিভাগটি এইচটিপি ইন্টারসেপ্টারে "নিয়মিত উপায়ে" ইনজেকশনের জন্য কোনও উপায় দেখায় বলে মনে হয়। "ইন্টারসেপ্টর" এর অধীনে তাদের কোড স্নিপেট দেখুন:

// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
  return {
    // optional method
    'request': function(config) {
      // do something on success
      return config || $q.when(config);
    },

    // optional method
   'requestError': function(rejection) {
      // do something on error
      if (canRecover(rejection)) {
        return responseOrNewPromise
      }
      return $q.reject(rejection);
    },



    // optional method
    'response': function(response) {
      // do something on success
      return response || $q.when(response);
    },

    // optional method
   'responseError': function(rejection) {
      // do something on error
      if (canRecover(rejection)) {
        return responseOrNewPromise
      }
      return $q.reject(rejection);
    };
  }
});

$httpProvider.interceptors.push('myHttpInterceptor');

উপরের কোডটি কোথায় যাওয়া উচিত?

আমার ধারণা আমার প্রশ্নটি এটি করার সঠিক উপায় কী?

ধন্যবাদ, এবং আমি আশা করি আমার প্রশ্নটি যথেষ্ট পরিষ্কার ছিল।


1
কৌতূহলের মাত্র বাইরে, কোন নির্ভরতা - যদি কোনও হয় - আপনি নিজের অथ সার্ভিসে কোথায় ব্যবহার করছেন? HTTP ইন্টারসেপ্টারে অনুরোধ পদ্ধতিটি ব্যবহার করে আমার বিজ্ঞপ্তি নির্ভরতা সংক্রান্ত সমস্যা ছিল, যা আমাকে এখানে এনেছে। আমি অ্যাঙ্গুলারফায়ারের $ ফায়ারবেসঅথ ব্যবহার করছি। আমি যখন ইনজেক্টর (লাইন 510) থেকে $ রুট ব্যবহার করে এমন কোডের ব্লকটি সরিয়ে ফেললাম, তখন সমস্ত কিছু কাজ শুরু করে। এখানে একটি সমস্যা আছে তবে এটি ইন্টারসেপ্টারে $ http ব্যবহার করার বিষয়ে। গিট অফ!
স্ল্যাম্বর্ন

এইচএম, এটির মূল্য কী, তার জন্য আমার ক্ষেত্রে AuthService $ উইন্ডো, $ এইচটিপি, $ অবস্থান, $ কিউ
শনলিম 9:34

আমি একটি কেস পেয়েছি যা কিছু পরিস্থিতিতে ইন্টারসেপ্টারে অনুরোধটি পুনরায় চেষ্টা করে, তাই এর উপর একটি আরও ছোট সার্কুলার নির্ভরতা রয়েছে $http। এর চারপাশের একমাত্র উপায়টি আমি ব্যবহার করেছি $injector.get, তবে এটি এড়াতে কোডটি গঠনের ভাল উপায় আছে কিনা তা জেনে রাখা ভাল।
মিশাল চেরেমজা

1
@ লিখিত থেকে প্রতিক্রিয়াটি একবার দেখুন: github.com/angular/angular.js/issues/2367 যা আমার জন্য অনুরূপ সমস্যা স্থির করেছে। তিনি যা করছেন তা হ'ল: $ http = $ http || injector.get $ ( "$ HTTP"); অবশ্যই আপনি own http প্রতিস্থাপন করতে পারেন আপনার নিজের পরিষেবার সাথে আপনি ব্যবহার করার চেষ্টা করছেন।
জোনাথন

উত্তর:


42

আপনার $ http এবং আপনার AuthService এর মধ্যে বিজ্ঞপ্তি নির্ভরতা রয়েছে।

আপনি $injectorপরিষেবাটি ব্যবহার করে যা করছেন তা হ'ল অউথ সার্ভিসে $ HT-র নির্ভরতা বিলম্ব করে মুরগি ও ডিমের সমস্যা সমাধান করা।

আমি বিশ্বাস করি যে আপনি যা করেছেন তা হ'ল এটি করার সহজতম উপায়।

আপনি এটি দ্বারা এটি করতে পারেন:

  • পরে ইন্টারসেপটর নিবন্ধন করা (কোনও run()ব্লকের পরিবর্তে একটি config()ব্লকে এটি করা ইতিমধ্যে কৌশলটি করতে পারে)। তবে আপনি কি গ্যারান্টি দিতে পারবেন যে $ HTTP ইতিমধ্যে কল করা হয়নি?
  • "ইনজেকশন" $ এইচটি সার্ভিসে ম্যানুয়ালি HTTP যখন আপনি কল AuthService.setHttp()বা কোনও কিছুর মাধ্যমে ইন্টারসেপটর নিবন্ধভুক্ত করেন ।
  • ...

15
এই উত্তরটি কীভাবে সমস্যার সমাধান করছে, আমি দেখিনি? @ শাওনলিম
ইনঙ্ক গুমাস

1
আসলে এটি এর সমাধান করছে না, এর ঠিক উল্লেখ করে যে অ্যালগরিদম প্রবাহটি খারাপ ছিল।
রোমান এম কোস

12
আপনি কোনও run()ব্লকে ইন্টারসেপ্টারটি নিবন্ধন করতে পারবেন না , কারণ আপনি কোনও রান ব্লকে $ httpPovider ইনজেক্ট করতে পারবেন না। আপনি কেবল কনফিগারেশন পর্যায়ে এটি করতে পারেন।
স্টিফেন ফ্রেডরিচ

2
ভাল পয়েন্ট পুনরায় বিজ্ঞপ্তি রেফারেন্স, তবে অন্যথায় এটি একটি গ্রহণযোগ্য উত্তর হওয়া উচিত নয়। বুলেট পয়েন্টগুলির
কোনওোটাই

65

এটিই আমি শেষ করেছিলাম

  .config(['$httpProvider', function ($httpProvider) {
        //enable cors
        $httpProvider.defaults.useXDomain = true;

        $httpProvider.interceptors.push(['$location', '$injector', '$q', function ($location, $injector, $q) {
            return {
                'request': function (config) {

                    //injected manually to get around circular dependency problem.
                    var AuthService = $injector.get('Auth');

                    if (!AuthService.isAuthenticated()) {
                        $location.path('/login');
                    } else {
                        //add session_id as a bearer token in header of all outgoing HTTP requests.
                        var currentUser = AuthService.getCurrentUser();
                        if (currentUser !== null) {
                            var sessionId = AuthService.getCurrentUser().sessionId;
                            if (sessionId) {
                                config.headers.Authorization = 'Bearer ' + sessionId;
                            }
                        }
                    }

                    //add headers
                    return config;
                },
                'responseError': function (rejection) {
                    if (rejection.status === 401) {

                        //injected manually to get around circular dependency problem.
                        var AuthService = $injector.get('Auth');

                        //if server returns 401 despite user being authenticated on app side, it means session timed out on server
                        if (AuthService.isAuthenticated()) {
                            AuthService.appLogOut();
                        }
                        $location.path('/login');
                        return $q.reject(rejection);
                    }
                }
            };
        }]);
    }]);

দ্রষ্টব্য: $injector.getকলগুলি ইন্টারসেপ্টারের পদ্ধতিগুলির মধ্যে থাকা উচিত, আপনি যদি সেগুলি অন্য কোথাও ব্যবহার করার চেষ্টা করেন তবে আপনি জেএসে একটি বিজ্ঞপ্তি নির্ভরতা ত্রুটি পেতে থাকবেন।


4
ম্যানুয়াল ইনজেকশন (ject injector.get ('Auth')) ব্যবহার করে সমস্যার সমাধান হয়েছে। ভাল কাজ!
রবার্ট

বিজ্ঞপ্তি নির্ভরতা এড়াতে আমি যা ইউআরএল আহ্বান করা হয়েছে তা যাচাই করছি। যদি (! এর জন্য আর কোনও বিজ্ঞপ্তি নির্ভরতা নেই। কমপক্ষে আমার জন্য এটি কাজ করেছে;)।
ব্রিয়ুক

পারফেক্ট। একই সমস্যাটি ঠিক করার জন্য আমার ঠিক এটিই দরকার ছিল। ধন্যবাদ @ শনলিম!
মার্টিন চেম্বারলিন

আমি এই সমাধানটি সত্যিই পছন্দ করি না কারণ তখন এই পরিষেবাটি বেনামে এবং পরীক্ষার জন্য হ্যান্ডেল পাওয়া তত সহজ নয়। রানটাইমে ইনজেকশন করার জন্য আরও ভাল সমাধান।
kmanzana

এটা আমার জন্য কাজ করেছে। মূলত the http ব্যবহার করা পরিষেবাটি ইনজেকশন করা using
টমাস

15

আমি মনে করি সরাসরি ইনজেক্টর ব্যবহার করা একটি অ্যান্টিপ্যাটার্ন।

বিজ্ঞপ্তি নির্ভরতা ভাঙার একটি উপায় হল একটি ইভেন্ট ব্যবহার করা: $ রাজ্যের ইনজেক্ট করার পরিবর্তে, ইনজেক্ট $ রুটস্কোপ। সরাসরি পুনর্নির্দেশের পরিবর্তে, করুন

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

যোগ

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

2
আমি মনে করি এটি আরও মার্জিত সমাধান, কারণ এটির কোনও নির্ভরতা থাকবে না, আমরা যেখানেই প্রাসঙ্গিক অনেক জায়গায় এই অনুষ্ঠানটি শুনতে পারি
বাসভ

এটি আমার প্রয়োজনের জন্য কাজ করবে না, কারণ কোনও ইভেন্ট প্রেরণের পরে আমার কোনও ফেরতের মান থাকতে পারে না।
xabitrigo

13

খারাপ যুক্তি এমন ফলাফল করেছে

প্রকৃতপক্ষে অনুসন্ধানের কোনও বিষয় নেই যা ব্যবহারকারী রচিত বা এইচটিটিপি ইন্টারসেপ্টারে নেই। আমি আপনার সমস্ত এইচটিটিপি অনুরোধগুলি একক। পরিষেবা (বা। কারখানায়, বা। প্রতিবার আপনি যখন ফাংশন কল করবেন তখন আপনি ব্যবহারকারী লগ ইন আছেন কিনা তা পরীক্ষা করতে পারবেন। সব ঠিক থাকলে অনুরোধ প্রেরণের অনুমতি দিন।

আপনার ক্ষেত্রে, কৌণিক অ্যাপ্লিকেশন যে কোনও ক্ষেত্রে অনুরোধ প্রেরণ করবে, আপনি কেবল সেখানে অনুমোদনের পরীক্ষা করছেন, এবং এর পরে জাভাস্ক্রিপ্ট অনুরোধ প্রেরণ করবেন।

আপনার সমস্যার মূল

myHttpInterceptor$httpProviderউদাহরণস্বরূপ বলা হয় । আপনার AuthServiceব্যবহারগুলি $http, বা $resource, এবং এখানে আপনার নির্ভরতা পুনরাবৃত্তি, বা বিজ্ঞপ্তি নির্ভরতা রয়েছে। আপনার যদি সেই নির্ভরতা অপসারণ হয় তবে AuthServiceতার চেয়ে বেশি আপনি ত্রুটিটি দেখতে পাবেন না।


@ পিটার হেরোইলেন নির্দেশিত হিসাবে, আপনি আপনার মডিউলটিতে এই ইন্টারসেপ্টারটি রাখতে পারেন module.run তবে এটি হ্যাকের মতো হবে, কোনও সমাধান নয়।

যদি আপনি পরিষ্কার এবং স্ব বর্ণনামূলক কোড করতে চান তবে আপনাকে অবশ্যই কিছু সলিড নীতি নিয়ে যেতে হবে।

কমপক্ষে একক দায়িত্বের নীতি আপনাকে এ জাতীয় পরিস্থিতিতে অনেক সাহায্য করবে।


5
আমি এই উত্তর ভাল worded হয় তা মনে করি না, কিন্তু আমি কি করতে এটা ইস্যু রুট পায় মনে করি। একটি প্রমাণীকরণ পরিষেবাদির সমস্যা যা বর্তমান ব্যবহারকারীর ডেটা এবং লগ ইন করার মাধ্যম (একটি http অনুরোধ) সংরক্ষণ করে তা হ'ল এটি দুটি জিনিসের জন্য দায়ী । যদি এটি পরিবর্তে বর্তমান ব্যবহারকারীর ডেটা সংরক্ষণ করার জন্য একটি পরিষেবা এবং লগ ইন করার জন্য অন্য একটি পরিষেবাতে বিভক্ত হয়, তবে HTTP ইন্টারসেপ্টারের কেবলমাত্র "বর্তমান ব্যবহারকারী পরিষেবা" এর উপর নির্ভরশীল, এবং আর কোনও বিজ্ঞপ্তি নির্ভরতা তৈরি করে না।
স্নিস্টোর

সিনিস্টর আপনাকে ধন্যবাদ! আরও পরিষ্কার করার জন্য আমার আরও ইংরেজি শেখা দরকার।
রোমান এম কোস

0

আপনি যদি কেবল অথ রাষ্ট্রের জন্য যাচাই করছেন (isAuthorised ()) আমি সেই রাজ্যটিকে একটি পৃথক মডিউলে রাখার পরামর্শ দিই, "আথ" বলুন, যা কেবলমাত্র রাজ্যটিকে ধারণ করে এবং $ http নিজেই ব্যবহার করে না।

app.config(['$httpProvider', function ($httpProvider) {
  $httpProvider.interceptors.push(function ($location, Auth) {
    return {
      'request': function (config) {
        if (!Auth.isAuthenticated() && $location.path != '/login') {
          console.log('user is not logged in.');
          $location.path('/login');
        }
        return config;
      }
    }
  })
}])

আথ মডিউল:

angular
  .module('app')
  .factory('Auth', Auth)

function Auth() {
  var $scope = {}
  $scope.sessionId = localStorage.getItem('sessionId')
  $scope.authorized = $scope.sessionId !== null
  //... other auth relevant data

  $scope.isAuthorized = function() {
    return $scope.authorized
  }

  return $scope
}

(আমি লোকালসটরেজটি এখানে ক্লায়েন্টের পাশে আইডিকে সঞ্চয় করতে ব্যবহার করেছি, তবে আপনি উদাহরণস্বরূপ $ http কল করার পরেও এটি আপনার AuthService এর ভিতরে সেট করতে পারেন)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.