Saya mencoba menulis pencegat HTTP untuk aplikasi AngularJS saya untuk menangani otentikasi.
Kode ini berfungsi, tetapi saya khawatir tentang menyuntikkan layanan secara manual karena saya pikir Angular seharusnya menangani ini secara otomatis:
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;
}
};
})
}]);
Apa yang saya mulai lakukan, tetapi mengalami masalah ketergantungan melingkar:
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');
});
Alasan lain mengapa saya khawatir adalah bahwa bagian di $ http di Angular Docs tampaknya menunjukkan cara untuk memasukkan dependensi dengan "cara biasa" ke dalam pencegat Http. Lihat cuplikan kodenya di bawah "Interceptors":
// 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');
Kemana perginya kode di atas?
Saya kira pertanyaan saya adalah apa cara yang benar untuk melakukan ini?
Terima kasih, dan saya harap pertanyaan saya cukup jelas.
javascript
angularjs
shaunlim.dll
sumber
sumber
$http
. Satu-satunya cara untuk mengatasinya yang saya temukan adalah dengan menggunakan$injector.get
, tetapi akan sangat bagus untuk mengetahui apakah ada cara yang baik untuk menyusun kode untuk menghindari hal ini.Jawaban:
Anda memiliki ketergantungan melingkar antara $ http dan AuthService Anda.
Apa yang Anda lakukan dengan menggunakan
$injector
layanan ini adalah memecahkan masalah ayam-dan-telur dengan menunda ketergantungan $ http pada AuthService.Saya percaya bahwa apa yang Anda lakukan sebenarnya adalah cara paling sederhana untuk melakukannya.
Anda juga bisa melakukan ini dengan:
run()
blok, bukan diconfig()
blok, mungkin sudah berhasil). Tetapi dapatkah Anda menjamin bahwa $ http belum dipanggil?AuthService.setHttp()
atau sesuatu.sumber
run()
blok, karena Anda tidak dapat menginjeksi $ httpProvider ke blok yang dijalankan. Anda hanya dapat melakukannya di fase konfigurasi.Inilah yang akhirnya saya lakukan
Catatan:
$injector.get
Panggilan harus berada dalam metode interseptor, jika Anda mencoba menggunakannya di tempat lain, Anda akan terus mendapatkan kesalahan dependensi melingkar di JS.sumber
Saya pikir menggunakan $ injektor secara langsung adalah antipattern.
Cara untuk memutus dependensi melingkar adalah dengan menggunakan peristiwa: Daripada memasukkan $ state, injeksikan $ rootScope. Alih-alih mengarahkan secara langsung, lakukan
plus
sumber
Logika buruk membuat hasil seperti itu
Sebenarnya tidak ada gunanya mencari apakah pengguna ditulis atau tidak di Http Interceptor. Saya akan merekomendasikan untuk membungkus semua permintaan HTTP Anda ke dalam satu .service (atau .factory, atau ke .provider), dan menggunakannya untuk SEMUA permintaan. Pada setiap kali Anda memanggil fungsi, Anda dapat memeriksa apakah pengguna masuk atau tidak. Jika semuanya baik-baik saja, izinkan kirim permintaan.
Dalam kasus Anda, aplikasi Angular akan mengirimkan permintaan dalam hal apa pun, Anda hanya memeriksa otorisasi di sana, dan setelah itu JavaScript akan mengirim permintaan.
Inti dari masalah Anda
myHttpInterceptor
disebut di bawah$httpProvider
contoh.AuthService
Penggunaan Anda$http
, atau$resource
, dan di sini Anda memiliki rekursi ketergantungan, atau ketergantungan melingkar. Jika Anda menghapus ketergantungan itu dariAuthService
, Anda tidak akan melihat kesalahan itu.Juga seperti yang ditunjukkan oleh @Pieter Herroelen, Anda dapat menempatkan pencegat ini di modul Anda
module.run
, tetapi ini lebih seperti peretasan, bukan solusi.Jika Anda ingin melakukan kode deskriptif dan bersih, Anda harus menggunakan beberapa prinsip SOLID.
Setidaknya prinsip Single Responsibility akan banyak membantu Anda dalam situasi seperti itu.
sumber
Jika Anda hanya memeriksa status Auth (isAuthorized ()), saya akan merekomendasikan untuk meletakkan status tersebut dalam modul terpisah, katakan "Auth", yang hanya menampung status dan tidak menggunakan $ http itu sendiri.
Modul Auth:
(saya menggunakan localStorage untuk menyimpan sessionId di sisi klien di sini, tetapi Anda juga dapat mengatur ini di dalam AuthService Anda setelah panggilan $ http misalnya)
sumber