Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular HTTP Client returning null inside interceptor

In the code below I have posted two examples of what the code is returning in the console. For an interceptor, I'm supposed to be returning an observable. I have converted the local storage promise into an observable using switchmap. I am still getting back null with this method. My observable is wrapped around the function, so I should be getting a value other than null. Thanks!

Interceptor.js

import { fromPromise } from 'rxjs/observable/fromPromise';

accessToken: string; 
emptyToken: any;


    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

//example

        this.storage.get('token').then((val) => {
             this.accessToken = val
            return console.log(this.accessToken, ' this is returning null value for token')
        })

//trying to return actual header
          return fromPromise(this.storage.get('token')).switchMap(access => {

            this.accessToken = access
            console.log(this.accessToken, ' this is returning null value for token')
            const authReq = req.clone({
                setHeaders: {
                Authorization: this.accessToken
                }
                });

                return next.handle(authReq)
           })
}
}

I've added the updated the code below, please ignore the code above and still getting the same result. As one of the answers said below, they are correct in all of their assumptions. It's boiled down to getting the token inside of the login observable. The issue is not with the interceptor, that code works fine. I need to somehow get my async value without returning null. The this.storage.ready() method gives me the same result as well. The auth service is being called after my interceptor, so therefore I don't have any token generated yet. How would I go about calling my auth service first?

login(userName: string, password: string, route: string = null): any {
     this.storage.set('tokens', 'able to retrieve this token value inside interceptor');

    this.logout(false);

    this.doLogin(userName, password)
      .subscribe(response => {

        let token:string = JSON.stringify(response.access_token);
        this.storage.set('token', token)

      }

      }

interceptor.ts

get(url: string, options?: RequestOptionsArgs): Observable<Response> {
  return Observable.fromPromise(
    this.getRequestOptionArgs(options)
  ).mergeMap((options) => {
    return super.get(url, options)
  })
  }

private getRequestOptionArgs(options?: RequestOptionsArgs) {
    return this.storage.get('token').then((token) => {
      console.log(token, 'token for the get')
      if (options == null) {
        options = new RequestOptions();
      }

      if (options.headers == null) {
        options.headers = new Headers();
      }

      if (token !== null) {
        options.headers.append('Authorization', 'Bearer ' + token);
      }
      options.headers.append('Content-Type', 'application/json');

      return options;
    });
  }
like image 722
userlkjsflkdsvm Avatar asked Sep 04 '17 04:09

userlkjsflkdsvm


1 Answers

I think the problem is that your StorageService is returning null, rather than this being a problem with the Interceptor.

The storage service is using a Promise, meaning it will only emit one value. If you are getting null then I guess you don't yet have the token in storage.

Where do you get the token from in the first place? The server? In which case this first request won't have the token.

But... you've said that when you access localStorage directly (synchronously) then you get a value and it all works. So I'm assuming you already have a token in storage.

Looking at the docs for Ionic Storage it looks like there is another possibility. The storage has a ready method, so perhaps the store isn't ready.

You could try something like this (untested) where you first wait for the ready promise to resolve before trying to get the token:

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

import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/observable/fromPromise';

@Injectable()
export class Interceptor implements HttpInterceptor {

    constructor (private storage: StorageService) {}

    intercept (request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // chain the ready promise with the get token promise
        return Observable.fromPromise(this.storage.ready().then(this.storage.get('token')))
            .mergeMap((token: string) => {

                const authReq = request.clone({
                    setHeaders: {
                        Authorization: token
                    }
                });

                return next.handle(authReq);

            });
    }
}

Just a guess...

like image 50
Daniel Crisp Avatar answered Oct 03 '22 16:10

Daniel Crisp