在HttpInterceptor中解析Promise报错,如何处理SecureStorage Token注入?
Hey there! Let's dig into this issue—it’s super common when mixing async Promise-based code (like SecureStorage) with RxJS-based Angular interceptors. That error is telling you your interceptor is returning undefined instead of a valid stream (Observable/Promise/Iterable), which happens when you don’t properly wrap the SecureStorage call into an Observable chain.
Let’s break down the fix step by step
First, let’s look at what’s probably causing the error. If your interceptor looked something like this, it’s definitely the culprit:
// ❌ Wrong approach - returns undefined! intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { this.secureStorage.get('token').then(token => { if (token) { request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } return next.handle(request); }); // No return statement here → returns undefined }
The problem is that secureStorage.get() returns a Promise, and you’re handling it with .then() without converting it to an Observable. The interceptor expects to return an Observable, so we need to bridge the Promise-to-Observable gap with RxJS.
Here’s the corrected implementation
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable, from, throwError } from 'rxjs'; import { switchMap, catchError } from 'rxjs/operators'; import { SecureStorage } from '@ionic-native/secure-storage/ngx'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private secureStorage: SecureStorage) {} intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // Convert your async token-fetching Promise to an Observable return from(this.getValidToken()).pipe( switchMap(token => { // Clone the request and add the token header if we have one const authRequest = token ? request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }) : request; // Pass the (modified) request to the next handler return next.handle(authRequest); }), catchError(error => { // Handle any errors from fetching the token (e.g., storage access issues) console.error('Failed to retrieve auth token:', error); return throwError(() => new Error('Token retrieval failed')); }) ); } // Your simplified token validation function (async/Promise-based) private async getValidToken(): Promise<string | null> { try { const token = await this.secureStorage.get('authToken'); // Add your expiration check logic here (you mentioned it's simplified) return token; } catch (err) { console.error('Error accessing secure storage:', err); return null; } } }
Key fixes explained
- Convert Promise to Observable: We use RxJS’s
from()operator to turn the Promise returned bygetValidToken()into an Observable—this keeps the entire interceptor flow within the RxJS ecosystem. - Use
switchMapfor async chaining: This operator lets us wait for the token to be fetched, then pass the modified request tonext.handle(), ensuring we return a valid Observable from the interceptor. - Handle edge cases: We explicitly handle scenarios where no token exists (pass the original request) and catch errors from SecureStorage to prevent the entire stream from breaking.
- Always return a stream: The entire
interceptmethod now returns an Observable, eliminating theundefinedthat caused your error.
Quick additional checks
- Make sure the key you use in
secureStorage.get()matches exactly what you used when storing the token (e.g.,'authToken'in the example). - If you’re using an older Ionic version, double-check that
SecureStorageis properly imported and initialized (thengxversion is required for Angular 6+).
内容的提问来源于stack exchange,提问作者Adrian Baginski

