Search code examples
node.jsangularrxjshttpresponse

http request with status 200 but no response data


I am trying to make an http request on refresh within my Angular frontend to a nodejs backend and expect to receive a token as response. Sometimes the request gets cancelled and even if its successful (200) i do not get send the token in the response.

When i make a postman request the request is always successful and sends the token, also when i make the request in Angular constructor without the refresh logic, so i suspect it has something to do with the usage of rxjs but can not figure out whats the problem.

here is the logic of refresh in app.component

constructor(
private router: Router,
private auth: AuthService
) {
// this.auth.requestServer(ServerMethod.GET, '/refresh').subscribe() // this request would work fine

router.events.pipe(
  switchMap((event) => {
    if (event instanceof NavigationStart) {
      const browserRefresh = !router.navigated;
      if (browserRefresh) {
        this.auth.deleteAccessToken();
        return this.auth.requestServer(ServerMethod.GET, '/refresh');
      }
    }
    return EMPTY;
  })
).subscribe();
}

here is deleteAccessToken()

deleteAccessToken() {
    sessionStorage.removeItem('accessToken');
    this.tokenSubject.next(null);
  }

requestServer()

  requestServer(type: ServerMethod, path?: string, data?: any): Observable<any> {
    let httpOptions: httpOptions;
    switch (type) {
      case ServerMethod.POST:
        return this.server.post(path, data).pipe(tap(res => this.handleAccessToken(res)));
      case ServerMethod.GETALL:
        return this.server.getAll(this.getAllPath);
      case ServerMethod.GET:
        return this.server.get(path).pipe(tap(res => this.handleAccessToken(res)));
      default:
        return EMPTY;
    }
  }

here is server get method

get(path: string): Observable<any> {
    const url = this.serverAdress + path;
    return this.http.get(url);
  }

and in my nodejs backend here is the refresh logic:

module.exports.refresh_get = async (req, res) => {
    if (req.cookies && req.cookies.refreshToken) {

        // Destructuring refreshToken from cookie
        const refreshToken = req.cookies.refreshToken;

        // Verifying refresh token
        jwt.verify(refreshToken, 'secret',
            (err, decodedToken) => {
                if (err) {

                    // Wrong Refesh Token
                    res.status(406).json({ message: 'wrong refresh token' });
                }
                else {
                    // create new accessToken
                    const accessToken = createToken(decodedToken.id);
                    // create new refreshToken and set it in cookie and delete old cookie
                    const newRefreshToken = jwt.sign({
                        id: decodedToken.id,
                    }, 'secret', { expiresIn: '1d' });
                    res.cookie('refreshToken', newRefreshToken, { httpOnly: true,
                        sameSite: 'None', secure: true,
                        maxAge: 24 * 60 * 60 * 1000 });
                    res.status(200).json({ accessToken });
                }
            })
    } else {
        res.status(406).json({ message: 'Unauthorized' });
    }
}

request in network tab on refresh looks then like this: enter image description here

but Response is empty, there should be an object { accessToken: '...' }


Solution

  • ChatGPT answered my question:

    It's possible that the problem lies with the switchMap operator in the router.events observable. The switchMap operator cancels the previous inner observable when a new value is emitted, which could result in the HTTP request being cancelled if it takes too long to complete.

    To ensure that the HTTP request is not cancelled, you can try using the concatMap operator instead of switchMap. concatMap will wait for the previous observable to complete before starting a new one, which will prevent the HTTP request from being cancelled prematurely.

    Thanks ChatGPT.