2017-08-10 37 views
2

如何使用新标头处理克隆请求?使用拦截器在Angular 4.3中重新尝试使用新标头的Http请求

我想在第一个请求失败后生成的新令牌在新的拦截器中执行克隆请求!

  • 如果犯错401 - >刷新令牌
  • 发回具有新标题

这里是我的尝试以前的请求的副本:

refreshSessionToken() { 
    return this.http.post('/connect', {}) 
     .map(res => { 
     const token = res.json(); 
     localStorage.setItem('token', token); 
     return token; 
     }); 
    } 


// Get the headers 
const headers = getAuthenticationHeaders(); 
const reqMain = req.clone({headers: headers}); 
return next.handle(reqMain).catch(err => { 

     this.refreshSessionToken() 
      .subscribe(token => { 
       const t = token.token_id; 
       const clonedReq = req.clone({headers: req.headers.set('access-token', t)}); 

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

得到一个日志clonedReq我可以看到该令牌已刷新,但订阅内的请求(clonedReq)未执行,为什么?!

我尝试了其他方法来刷新智威汤逊,但它似乎并没有在我的情况下工作,对如何处理它的任何帮助?

谢谢!

我的结果是什么?

  • 发送1#HTTP请求
  • 1#请求失败
  • 刷新令牌(获取/设置令牌)
  • 克隆先前请求并添加刷新令牌
  • 发送2#HTTP请求
  • 2#请求成功

Simil IAR问题:

http-interceptor-refresh-jwt-token

+1

如果返回next.handle(clonedReq);是可观察的(我怀疑是什么),那么你将需要订阅它.. – codeSetter

+0

@Dipak有道理!感谢:D:D 现在克隆的请求被触发,并且2#请求结果成功。 - 订阅中的日志被激发两次(HTTP请求只发送一次..所以它很好),但我不确定它为什么会发生? 'next.handle(clonedReq) .subscribe(()=> console.log('Cloned Request Fired Twice!'));' – 39ro

+0

内部回报是罪魁祸首,你这样做的方式是混乱的......虽然它可以工作,但我不喜欢它。他们是更好的方式...我会回答一旦我回家...等等... – codeSetter

回答

4

继通用方法可用于拦截以及添加/删除附加信息调用和响应。

好的,这里是完整的代码。

InterceptedHttp.ts


import { Injectable } from "@angular/core"; 
import { RequestOptions, Http, Headers, Response, RequestMethod, URLSearchParams } from "@angular/http"; 
import { Observable, Observer } from 'rxjs/Rx'; 

import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/catch'; 
import "rxjs/add/operator/mergeMap"; 

@Injectable() 
export class InterceptedHttp { 

    constructor(private http: Http) { } 

    getRequestOption(method: RequestMethod | string, data?: any, params?: any): RequestOptions { 
     let options = new RequestOptions(); 
     options.headers = new Headers(); 
     //options.headers.append('Content-Type', 'application/json'); 
     options.method = method; 

     let token: string = localStorage.getItem('token'); 
     //if (token) options.headers.append('Authorization', 'Bearer ' + token); 

     if (data) options.body = data; 

     if (params) { 
      options.search = new URLSearchParams(); 
      let keys: string[] = Object.keys(params); 

      keys.forEach((key, index) => { 
       options.search.set(key, params[key]); 
      }); 
     } 

     return options; 
    } 

    refreshSessionToken(): Observable<string> { 
     //Put some user identification data 
     let userData: any = {id: 'abc'}; 
     return this.http.post('/refreshToken', userData) 
      .map(res => { 
       let token = res.json(); 
       localStorage.setItem('token', token); 
       return token; 
      }); 
    } 

    getApiResponse<T>(url: string, method: RequestMethod | string, data?: Object): Observable<T> { 
     let op1: RequestOptions = this.getRequestOption(method, data); 
     return this.http.request(url, op1) 
      .catch((err) => { 
       // UnAuthorised, 401 
       if (err.status == 401) { 
        return this.refreshSessionToken().flatMap(t => { 
         let op2 = this.getRequestOption(method, data); 
         return this.http.request(url, op2); 
        }); 
       } 
       throw err; 
      }) 
      .map((response: Response) => { 
       let ret: T = response.json(); 
       return ret; 
      }); 
    } 

    get<T>(url: string): Observable<T> { 
     return this.getApiResponse<T>(url, RequestMethod.Get); 
    } 

    post<T, R>(url: string, body: T): Observable<R> { 
     return this.getApiResponse<R>(url, RequestMethod.Post, body); 
    } 

    put<T, R>(url: string, body: T): Observable<R> { 
     return this.getApiResponse<R>(url, RequestMethod.Put, body); 
    } 

    delete<T>(url: string): Observable<T> { 
     return this.getApiResponse<T>(url, RequestMethod.Delete); 
    } 
} 

DataService.ts

import { Injectable } from '@angular/core'; 
    import { Observable } from 'rxjs/Observable'; 
    import { User } from './User'; 
    import { InterceptedHttp } from './http.interceptor'; 

    @Injectable() 
    export class DataService { 
     constructor(private apiHandler: InterceptedHttp) { } 

     getAll(): Observable<User[]> { 
      return this.apiHandler.get<User[]>('http://mocker.egen.io/users'); 
     } 
    } 

用户。TS

export class User { 
     id?: number; 

     firstName?: string; 

     lastName?: string; 
    } 

AppComponent.ts

import { Component } from '@angular/core'; 
    import { DataService } from './user-data.service'; 
    import { User } from './User'; 

    @Component({ 
     selector: 'app-root', 
     templateUrl: './app.component.html', 
     styleUrls: ['./app.component.css'] 
    }) 
    export class AppComponent { 
     title = 'app works!'; 
     users: User[]; 

     constructor(dataService: DataService){ 
     dataService.getAll().subscribe((u) => { 
      this.users = u; 
     }); 
     } 
    } 

app.component.html

<h1> 
    <table> 
    <tr *ngFor="let item of users; let i = index"> 
     <td> {{item.firstName}} </td> 
    </tr> 
    </table> 
</h1> 
+0

我需要说我不是承诺的忠实粉丝,也许是因为我没有找到足够的时间或场景来玩! 我没有真正理解为什么一切都被包装在一个getApiResponse而不是拦截中...... 它是否像一个单独的方法,它被触发到一个静态端点,以检查在发送到Api之前该令牌是否仍然有效一个真正的要求? – 39ro

+0

那么,它明显的选择在Angular应用中使用observable和promise。 http.get文章和所有回报承诺...您需要了解如何构建承诺...应该完成这项工作。我给出的例子完全符合你的要求。信不信由你在没有你知识的情况下使用诺言 – codeSetter

+0

经过几天的测试我仍然处于相同的情况......我真的不明白你的解决方案,以及何时需要解雇getApiResponse! 这看起来与用于HTTP拦截器的旧逻辑中使用的刷新令牌相同! [GitHub库 - 刷新令牌逻辑(https://gist.github.com/lucassus/d42069763c81a6e6bc68046793893c2c) 其中一个错误的使用溶液'''克隆不上型Observable''' – 39ro

0

我回答了类似的问题here

您无法将克隆的请求传递到下一个处理程序。相反,使用HttpClient重新尝试克隆的请求。

this.http.request(clonedReq).subscribe(......); 
相关问题