HttpClient 拦截器强制请求重复 [英] HttpClient Interceptor forces request duplicates

查看:53
本文介绍了HttpClient 拦截器强制请求重复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢使用 HttpInterceptor (Angular 6),它添加授权标头但也处理 401 以重定向到登录页面.这是我的代码:

从'@angular/core'导入{Injectable};从@angular/common/http"导入 {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest};从 'rxjs' 导入 {Observable};从 '@angular/router' 导入 {Router};@Injectable()导出类 JwtInterceptor 实现 HttpInterceptor {构造函数(私有路由器:路由器){}拦截(请求:HttpRequest,下一个:HttpHandler):Observable>{//如果可用,添加带有 jwt 令牌的授权标头让 currentUser = JSON.parse(localStorage.getItem('currentUser'));if (currentUser && currentUser.token) {请求 = request.clone({设置标题:{授权:`Bearer ${currentUser.token}`,},});}const req = next.handle(request);//---------------- VVV ---------------req.subscribe(() => {}, (错误: 任何) =>{if (error instanceof HttpErrorResponse && (error as HttpErrorResponse).status === 401)this.router.navigate(['public/login']);});//---------------- ^^^ ---------------返回请求;}}

一切正常,除非 vvv/^^^ 注释中的代码强制请求发送两次.为什么这个?好的,我可能必须订阅请求,因为这个拦截器订阅了我的服务,可能是使用 HttpClient.有没有更好的方法来解决这个问题?

以下是 package.json 中的依赖项:

<预><代码>..."@angular/compiler": "6.0.3","@angular/core": "6.0.3","@angular/http": "6.0.3","@angular/router": "6.0.3","rxjs": "^6.2.0","rxjs-compat": "^6.2.0","rxjs-tslint": "^0.1.4",zone.js":^0.8.26"...

解决方案

你应该使用 do() 而不是 subscribe()

intercept(request: HttpRequest, next: HttpHandler): Observable>{//如果可用,添加带有 jwt 令牌的授权标头让 currentUser = JSON.parse(localStorage.getItem('currentUser'));if (currentUser && currentUser.token) {请求 = request.clone({设置标题:{授权:`Bearer ${currentUser.token}`,},});}return next.handle(request).do((event: HttpEvent) => {如果(HttpResponse 的事件实例){//如果你愿意,可以做一些带有响应的事情}}, (错误:任何) =>{if (err instanceof HttpErrorResponse {如果(错误.状态 === 401){this.router.navigate(['public/login']);}}});}

do() 和 subscribe() 的区别

编辑

import do operator import { do } from 'rxjs/operators';

为什么/tap 在用作订阅时会被忽略?

这里的重点是 do() 不会影响流的流动,不像其他操作符.它接受响应,做一些事情,即使它修改了响应,流也会忽略它.当您尝试将其用作 subscribe() 时,它会被忽略,因为您已经在下面的语句中返回了流

I like to have a HttpInterceptor (Angular 6), which adds Authorization Headers but also handles 401 to redirect to login page. This is my code:

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

@Injectable()
export class JwtInterceptor implements HttpInterceptor {


    constructor(private router: Router) {
    }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // add authorization header with jwt token if available
        let currentUser = JSON.parse(localStorage.getItem('currentUser'));
        if (currentUser && currentUser.token) {
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${currentUser.token}`,
                },
            });
        }

        const req = next.handle(request);

        // ---------------- VVV ---------------
        req.subscribe(() => {
        }, (error: any) => {
            if (error instanceof HttpErrorResponse && (error as HttpErrorResponse).status === 401)
                this.router.navigate(['public/login']);
        });
        // ---------------- ^^^ ---------------

        return req;
    }
}

All works fine execpt that the code inside the vvv / ^^^ comment enforces that the request is sent twice. Why this? OK, I probably have to subscriptions on the request because this interceptor subscribes and probably my service using the HttpClient. Is there a bether way to solve this?

Edit: Here are the dependencies from package.json:

...
"@angular/compiler": "6.0.3",
"@angular/core": "6.0.3",
"@angular/http": "6.0.3",
"@angular/router": "6.0.3",
"rxjs": "^6.2.0",
"rxjs-compat": "^6.2.0",
"rxjs-tslint": "^0.1.4",
"zone.js": "^0.8.26"
...

解决方案

You should use do() instead of subscribe()

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 
   // add authorization header with jwt token if available
        let currentUser = JSON.parse(localStorage.getItem('currentUser'));
        if (currentUser && currentUser.token) {
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${currentUser.token}`,
                },
            });
        }
  return next.handle(request).do((event: HttpEvent<any>) => {
    if (event instanceof HttpResponse) {
      // do stuff with response if you want
    }
  }, (err: any) => {
    if (err instanceof HttpErrorResponse {
      if (err.status === 401) {
        this.router.navigate(['public/login']);
      }
    }
  });
}

Difference between do() and subscribe()

Edit

import do operator import { do } from 'rxjs/operators';

Why do/tap get ignored when used as subscribe?

The point here is that do() will not affect the flow of the stream, unlike other operators. It takes the response, does something and even if it modifies the response the stream is going to ignore it. When you try to use it as subscribe() it simply get's ignored as you have already returned stream in below statement

这篇关于HttpClient 拦截器强制请求重复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆