Navigate to the logout page upon encountering an error during the request

I recently upgraded our application from angular 2 to angular 5 and also made the switch from the deprecated Http module to the new HttpClient.

In the previous version of the application, I used the Http-Client to redirect to a specific page in case of errors.

import {Router} from "@angular/router";
import {Injectable} from "@angular/core";
import {ConnectionBackend, Http, Request, RequestOptions, RequestOptionsArgs, Response} from "@angular/http";
import {Observable} from "rxjs/Observable";
import "rxjs/add/operator/catch";

@Injectable()
export class HttpService extends Http {

  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private router: Router) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    return super.request(url, options)
      .catch(this.catchErrors());
  }

  private catchErrors() {
    return (res: Response) => {
      if (this.isError(res)) {
        console.log(`Internal server error occurred (${res.status} - ${res.statusText})`);
        this.router.navigateByUrl('/error');
      } else if (this.isUnauthorized(res)) {
        console.log(`User is not authenticated - either not logged in or session expired (${res.status} - ${res.statusText})`);
        this.router.navigateByUrl('/logout');
      } else if (this.isForbidden(res)) {
        console.log(`User does not have necessary permissions for the resource (${res.status} - ${res.statusText}): ${res.url}`);
        this.router.navigateByUrl('/forbidden');
      }

      return Observable.throw(res);
    };
  }

  private isError(res: Response): boolean {
    return res && res.status === 500;
  }

  private isUnauthorized(res: Response): boolean {
    return res && res.status === 401;
  }

  private isForbidden(res: Response): boolean {
    return res && res.status === 403;
  }

}

After the upgrade, I have refactored this functionality to use an HttpInterceptor instead.

import {Router} from "@angular/router";
import {Injectable} from "@angular/core";
import {Observable} from "rxjs/Observable";
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from "@angular/common/http";

@Injectable()
export class HttpService implements HttpInterceptor {

  constructor(private router: Router) {
  }

  private catchErrors() {
    return (res: HttpResponse<any>) => {
      if (this.isError(res)) {
        console.log(`Internal server error occurred (${res.status} - ${res.statusText})`);
        this.router.navigateByUrl('/error');
      } else if (this.isUnauthorized(res)) {
        console.log(`User is not authenticated - either not logged in or session expired (${res.status} - ${res.statusText})`);
        this.router.navigateByUrl('/logout');
      } else if (this.isForbidden(res)) {
        console.log(`User does not have necessary permissions for the resource (${res.status} - ${res.statusText}): ${res.url}`);
        this.router.navigateByUrl('/forbidden');
      }

      return Observable.throw(res);
    };
  }

  private isError(res: HttpResponse<any>): boolean {
    return res && res.status === 500;
  }

  private isUnauthorized(res: HttpResponse<any>): boolean {
    return res && res.status === 401;
  }

  private isForbidden(res: HttpResponse<any>): boolean {
    return res && res.status === 403;
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).catch(this.catchErrors());
  }

}

However, after implementing this change, the navigateByUrl method seems to have no effect and the site remains accessible even after encountering errors.

Any suggestions on how to address this issue would be greatly appreciated.

Answer №1

Check out this potential solution:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const started = Date.now();
        /**
         * Handle the new request with any updated headers
         */
        return next.handle(req).do((event: HttpEvent<any>) => {
            /**
             * Successful HTTP Response Time
             */
            if (event instanceof HttpResponse) {
                const elapsed = Date.now() - started;
            }

        }, (err: any) => {
            /**
             * Redirect to error_handling route based on error status or error_code
             */
            if (err instanceof HttpErrorResponse) {
                switch (err.status) {
                    case 500:
                        console.log(`Internal server error occurred (${err.status} - ${err.statusText})`);
                        this.router.navigateByUrl('/error');
                        break;
                    case 400:
                        console.log(`User not authenticated - either not logged in or session expired (${err.status} - ${err.statusText})`);
                        this.router.navigateByUrl('/logout');
                        break;
                    case 403:
                        console.log(`User lacks necessary permissions for the resource (${err.status} - ${err.statusText}): ${err.url}`);
                        this.router.navigateByUrl('/forbidden');
                        break;
                }
            }
        });
}

Answer №2

No console error message appeared?

Perhaps you could experiment with the code below:

import {Router} from "@angular/router";
import {Injectable} from "@angular/core";
import {Observable} from "rxjs/Observable";
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from "@angular/common/http";


@Injectable()
export class HttpService implements HttpInterceptor {

  constructor(private router: Router) {
  }

  private handleErrors(httpError) {
      if (this.isError(res)) {
        console.log(`Internal server error occurred (${res.status} - ${res.statusText})`);
        this.router.navigateByUrl('/error');
      } else if (this.isUnauthorized(res)) {
        console.log(`User is not authenticated - possibly not logged in or the session expired? (${res.status} - ${res.statusText})`);
        this.router.navigateByUrl('/logout');
      } else if (this.isForbidden(res)) {
        console.log(`User lacks necessary permissions for the resource (${res.status} - ${res.statusText}): ${res.url}`);
        this.router.navigateByUrl('/forbidden');
      }

      return Observable.throw(res);
  }

  private isError(res: HttpResponse<any>): boolean {
    return res && res.status === 500;
  }

  private isUnauthorized(res: HttpResponse<any>): boolean {
    return res && res.status === 401;
  }

  private isForbidden(res: HttpResponse<any>): boolean {
    return res && res.status === 403;
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).catch(httpError => this.handleErrors(httpError));
  }

}

To ensure functionality, confirm that the handleErrors function is properly connected to the HttpService class and execute Observable.throw to return an unsuccessful Observable.

Furthermore, validate the type of httpError. In Angular 6 and above, I utilize HttpErrorResponse, but the older versions may require a different type.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is preventing me from assigning to a class variable within a $http success handler?

During the course of my project, I have encountered a perplexing situation that is difficult to comprehend. My intuition tells me that the issue lies in a peculiar nuance of javascript while I am working in TypeScript. Unfortunately, I am unable to prove t ...

The `createAction` function does not preserve the data type when used with `ofType`

I'm currently developing a mobile application that allows users to choose snacks from a list of available options retrieved from an external API. To handle actions and dispatch API requests, I am utilizing redux-observable. Below is my existing code, ...

BrowserRouter - The type '{ children: Element; }' is not compatible with the type 'IntrinsicAttributes', as they do not share any properties in common

After upgrading to React version 18, I encountered a type error with the BrowserRouter component. Despite trying various approaches, I am unable to pinpoint the root of the problem. Here is the error that pops up during debugging: Overload 1 of 2, &a ...

Exploring through objects extensively and expanding all their values within Angular

I am in need of searching for a specific value within an object graph. Once this value is found, I want to set the 'expanded' property to true on that particular object, as well as on all containing objects up the object graph. For example, give ...

The image hover feature is not functioning as expected in Angular 4

Currently, I am involved in a project using Angular 4. One particular section involves changing images on hover. Although I have implemented the following code, it does not seem to be functioning correctly for me. Interestingly, the same code works perfect ...

When attempting to send a token from an account to a marketplace in ERC721, the transfer caller must either be the owner

Currently, I am in the process of transferring my NFT to a marketplace pragma solidity ^0.8.7; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import & ...

Typescript React Union type

I have developed a Card component with two different variants: Wrapper and Dashboard. Each variant comes with its own set of props. export type DashboardProps = { variant: CardVariant.Dashboard, primaryText: string, secondaryText: string, icon: Ove ...

NodeJS function does not pause for the PostgreSQL database call despite using await keyword

I am attempting to recursively insert entries into the database where each entry depends on the previous one (the ID of the previous entry will be the child_id of the next entry). However, I am facing difficulties in getting async/await to work correctly. ...

Issue: Incompatibility between React and TypeScript leading to an error message - "No

When I try to map through an array in my code, I encounter a significant error as shown below: // Home.tsx render() { const { inputs, outputs, expectedOutputs } = this.state; return ( <ContentContainer> {inputs.map((inpu ...

Angular-template static functions refer to functions that do not require an

Our project utilizes the linting-config provided by AirBnB. There is a rule that stipulates class methods must utilize this or be declared as static. While this rule theoretically makes sense, it seems to present challenges within an angular context. Consi ...

A guide to adjusting the font size and placement of text in a precise manner

Is there a way to adjust the font size and position in a particular text? How can this be achieved? doc.text( 40, 30, "jspdf" ); https://i.stack.imgur.com/Io7RE.png ...

Customizing the default font color in Angular Material

I am currently navigating through theming in Angular Material and feeling a bit disoriented. I have implemented the prebuilt indigo-pink theme by importing it into my styles.scss as shown below: @import "~@angular/material/prebuilt-themes/indigo-pink.css" ...

How to adjust the font size and font style for the [pageSizeOption] in mat-paginator

I am having trouble adjusting the font-size of the [pageSizeOptions] in my mat-paginator element in the application. <mat-paginator [pageSizeOptions]="[10, 20, 30]"></mat-paginator> The "10" appears too small compared to the text "items per p ...

Angular doesn't support this particular type as an injection token

I'm attempting to create a constructor with a type of string, but I keep encountering the following error: This particular type is not supported as an injection token @Injectable({providedIn: 'root'}) export class DataService { const ...

Make sure to verify if the mode in Angular is either visible-print or hidden-print

Here is a snippet of code <div class="row"> <div class="col-sm-12 visible-print"> Content (display in full width when printed) </div> <div class="col-sm-6 hidden-print"> Content (same as above but only half width when ...

I'm encountering an error in TestCafe that says "TypeError: Cannot read properties of undefined (reading 'match')". Which specific segment of my code is causing this issue?

retrieveUrlFromEmailData(emailData:any){ const emailContent = emailData.email_text; const urlPattern = /(https?:\/\/[^\n]*)/; const foundUrl = emailContent.match(urlPattern)[0]; return foundUrl } ...

I'm encountering problems with downgrading packages in Angular 4

Recently, I inherited an Angular project from my company. Despite being new to Angular, I tried starting the project after running npm install. However, I encountered the error below and provided details of my package in hopes of receiving instructions to ...

What is the best way to reset the testing subject between test cases using Jest and TypeScript?

I'm currently utilizing typescript alongside jest for unit testing. My goal is to create a simple unit test, but it consistently fails no matter what I try. Below is the snippet of code in question: // initialize.ts let initialized = false; let secre ...

A programming element that is capable of accessing a data member, but mandates the use of a setter method for modifications

I am unsure whether I need a class or an interface, but my goal is to create an object with a member variable that can be easily accessed like a regular variable. For example: interface LineRange { begin: number; end: number; } However, I want th ...

Encountering an error in testing with Typescript, Express, Mocha, and Chai

After successfully creating my first server using Express in TypeScript, I decided to test the routes in the app. import app from './Server' const server = app.listen(8080, '0.0.0.0', () => { console.log("Server is listening on ...