$conf, $runtime; function_exists('chdir') AND chdir(APP_PATH); $r = 'mysql' == $conf['cache']['type'] ? website_set('runtime', $runtime) : cache_set('runtime', $runtime); } function runtime_truncate() { global $conf; 'mysql' == $conf['cache']['type'] ? website_set('runtime', '') : cache_delete('runtime'); } register_shutdown_function('runtime_save'); ?>javascript - next.handle(request) in multiple HTTP interceptors fails: undefined - Stack Overflow|Programmer puzzle solving
最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - next.handle(request) in multiple HTTP interceptors fails: undefined - Stack Overflow

matteradmin12PV0评论

In a project, I work with 2 HTTP interceptors: 1 to add a JWT token to each request, the other to intercept an ining 401 error status.

I call a separate program to get all feedback for my app in this service:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/mon/http';

import { environment } from '@environments/environment';
import { Feedback } from '@app/_models/feedback';

@Injectable({ providedIn: 'root' })
export class FeedbackService {
    constructor(
        private http: HttpClient
    ) {}

    getAll() {
        return this.http.get<Feedback[]>(`${environment.apiUrl}/feedback`);
    }

    getById(id: string) {
        return this.http.get<Feedback>(`${environment.apiUrl}/feedback/${id}`);
    }

    delete(id: string) {
        return this.http.delete(`${environment.apiUrl}/feedback/${id}`);
    }
}

The JWT interceptor:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/mon/http';
import { Observable } from 'rxjs';

import { environment } from '@environments/environment';
import { AuthorizationService } from 'src/shared/authorization.service';

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    constructor(private auth: AuthorizationService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // add auth header with jwt if user is logged in and request is to the api url
        const authenticatedUser = this.auth.getAuthenticatedUser();
        if (authenticatedUser == null) {
            return;
        }
        authenticatedUser.getSession( (err, session) => {
            if (err) {
                console.log(err);
                return;
            }
            const isApiUrl = request.url.startsWith(environment.apiUrl);
            const token = session.getIdToken().getJwtToken();
            const headers = new Headers();
            headers.append('Authorization', token);
            if (this.auth.isLoggedIn() && isApiUrl) {
                request = request.clone({
                    setHeaders: {
                        Authorization: token,
                    }
                });
            }

            return next.handle(request);
        });
    }
}

The Error interceptor:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/mon/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

import { AccountService } from '@app/_services';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
    constructor(private accountService: AccountService) {}

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        console.log(next.handle(request));
        return next.handle(request).pipe(catchError(err => {
            if (err.status === 401) {
                // auto logout if 401 response returned from api
                this.accountService.logout();
            }

            const error = err.error.message || err.statusText;
            return throwError(error);
        }));
    }
}

When I provide both interceptors in my app.module,

{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },

I always get an error saying the following below. This happens because next.handle(request) apparently is undefined, and I don't really know why. Using only the Error interceptor works with no issue.

ERROR TypeError: Cannot read property 'pipe' of undefined
    at ErrorInterceptor.intercept (error.interceptor.ts:14)
    at HttpInterceptorHandler.handle (http.js:1958)
    at HttpXsrfInterceptor.intercept (http.js:2819)
    at HttpInterceptorHandler.handle (http.js:1958)
    at HttpInterceptingHandler.handle (http.js:2895)
    at MergeMapSubscriber.project (http.js:1682)
    at MergeMapSubscriber._tryNext (mergeMap.js:46)
    at MergeMapSubscriber._next (mergeMap.js:36)
    at MergeMapSubscriber.next (Subscriber.js:49)
    at Observable._subscribe (subscribeToArray.js:3)

Using only the JwtInterceptor gives following error, which I can't figure out where it's ing from. Of course, I would want to use both. Am I missing something while configuring the multiple interceptors?

ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    at subscribeTo (subscribeTo.js:27)
    at subscribeToResult (subscribeToResult.js:11)
    at MergeMapSubscriber._innerSub (mergeMap.js:59)
    at MergeMapSubscriber._tryNext (mergeMap.js:53)
    at MergeMapSubscriber._next (mergeMap.js:36)
    at MergeMapSubscriber.next (Subscriber.js:49)
    at Observable._subscribe (subscribeToArray.js:3)
    at Observable._trySubscribe (Observable.js:42)
    at Observable.subscribe (Observable.js:28)
    at MergeMapOperator.call (mergeMap.js:21)

In a project, I work with 2 HTTP interceptors: 1 to add a JWT token to each request, the other to intercept an ining 401 error status.

I call a separate program to get all feedback for my app in this service:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/mon/http';

import { environment } from '@environments/environment';
import { Feedback } from '@app/_models/feedback';

@Injectable({ providedIn: 'root' })
export class FeedbackService {
    constructor(
        private http: HttpClient
    ) {}

    getAll() {
        return this.http.get<Feedback[]>(`${environment.apiUrl}/feedback`);
    }

    getById(id: string) {
        return this.http.get<Feedback>(`${environment.apiUrl}/feedback/${id}`);
    }

    delete(id: string) {
        return this.http.delete(`${environment.apiUrl}/feedback/${id}`);
    }
}

The JWT interceptor:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/mon/http';
import { Observable } from 'rxjs';

import { environment } from '@environments/environment';
import { AuthorizationService } from 'src/shared/authorization.service';

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    constructor(private auth: AuthorizationService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // add auth header with jwt if user is logged in and request is to the api url
        const authenticatedUser = this.auth.getAuthenticatedUser();
        if (authenticatedUser == null) {
            return;
        }
        authenticatedUser.getSession( (err, session) => {
            if (err) {
                console.log(err);
                return;
            }
            const isApiUrl = request.url.startsWith(environment.apiUrl);
            const token = session.getIdToken().getJwtToken();
            const headers = new Headers();
            headers.append('Authorization', token);
            if (this.auth.isLoggedIn() && isApiUrl) {
                request = request.clone({
                    setHeaders: {
                        Authorization: token,
                    }
                });
            }

            return next.handle(request);
        });
    }
}

The Error interceptor:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/mon/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

import { AccountService } from '@app/_services';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
    constructor(private accountService: AccountService) {}

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        console.log(next.handle(request));
        return next.handle(request).pipe(catchError(err => {
            if (err.status === 401) {
                // auto logout if 401 response returned from api
                this.accountService.logout();
            }

            const error = err.error.message || err.statusText;
            return throwError(error);
        }));
    }
}

When I provide both interceptors in my app.module,

{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },

I always get an error saying the following below. This happens because next.handle(request) apparently is undefined, and I don't really know why. Using only the Error interceptor works with no issue.

ERROR TypeError: Cannot read property 'pipe' of undefined
    at ErrorInterceptor.intercept (error.interceptor.ts:14)
    at HttpInterceptorHandler.handle (http.js:1958)
    at HttpXsrfInterceptor.intercept (http.js:2819)
    at HttpInterceptorHandler.handle (http.js:1958)
    at HttpInterceptingHandler.handle (http.js:2895)
    at MergeMapSubscriber.project (http.js:1682)
    at MergeMapSubscriber._tryNext (mergeMap.js:46)
    at MergeMapSubscriber._next (mergeMap.js:36)
    at MergeMapSubscriber.next (Subscriber.js:49)
    at Observable._subscribe (subscribeToArray.js:3)

Using only the JwtInterceptor gives following error, which I can't figure out where it's ing from. Of course, I would want to use both. Am I missing something while configuring the multiple interceptors?

ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    at subscribeTo (subscribeTo.js:27)
    at subscribeToResult (subscribeToResult.js:11)
    at MergeMapSubscriber._innerSub (mergeMap.js:59)
    at MergeMapSubscriber._tryNext (mergeMap.js:53)
    at MergeMapSubscriber._next (mergeMap.js:36)
    at MergeMapSubscriber.next (Subscriber.js:49)
    at Observable._subscribe (subscribeToArray.js:3)
    at Observable._trySubscribe (Observable.js:42)
    at Observable.subscribe (Observable.js:28)
    at MergeMapOperator.call (mergeMap.js:21)
Share Improve this question asked Jun 29, 2020 at 10:12 JasperRJasperR 3692 gold badges6 silver badges17 bronze badges 1
  • JwtInterceptor.intercept() doesn't always return an Observable. – martin Commented Jun 29, 2020 at 12:11
Add a ment  | 

1 Answer 1

Reset to default 1

Rewrite your JwtInterceptor:

import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent } from '@angular/mon/http';
import { Injectable } from '@angular/core';
import { Observable, from } from 'rxjs';

import { environment } from '@environments/environment';
import { AuthorizationService } from 'src/shared/authorization.service';


@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    constructor(private auth: AuthorizationService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return from(this.getSessionWithAuthReq(request, next));
    }

    async getSessionWithAuthReq(request: HttpRequest<any>, next: HttpHandler){
        const authenticatedUser = this.auth.getAuthenticatedUser();
        
        if (authenticatedUser) {
            const authRequest:  HttpRequest<any>  = await new Promise( (resolve) => {
                authenticatedUser.getSession( (err, session) => {
                    if (err) {
                        console.log(err);
                        // want to go on without authenticating if there is an error from getting session 
                        return resolve(request);
                    }
                    const isApiUrl = request.url.startsWith(environment.apiUrl);
                    const token = session.getIdToken().getJwtToken();
                    const headers = new Headers();
                    headers.append('Authorization', token);
                    if (this.auth.isLoggedIn() && isApiUrl) {
                        const req = request.clone({
                            setHeaders: {
                                Authorization: token,
                            }
                        });
                        return resolve(req);
                    }
                    return resolve(request);
                });
            });
            
            
            return next.handle(authRequest).toPromise();
        }

        return next.handle(request).toPromise();
    }
}
Post a comment

comment list (0)

  1. No comments so far