Angular改造Http实现RESTful认证

在上篇Angular拦截器实现RESTful认证中,通过替换了Http的提供器来拦截了Http请求,并且重新实现ConnectionBackend抽象类,并用它发起请求来达到了统一对请求进行拦截处理的功能。
但是那种实现存在问题:

Angular拦截器存在的问题

但是在实际应用中发现,使用这种方案会导致每次请求都会被发送两次。调试后发现原因如下:

  • Angular应用中Http返回的是一个Observable流对象,此对象的实现是RXjs封装的
  • 而在RXjs中对Observable的处理是冷模式,即被订阅后才发送请求。
  • 之前的拦截器实现会直接在创建对象时就直接发送请求,被订阅时又再次发送请求
    这一问题导致了比如发送一条向数据库中插入数据的http请求时,第一条请求插入了数据,第二条请求被返回数据已经存在的错误。客户端接收到数据已经存在的错误,对视图进行错误的更新。

改造Http实现对请求和结果预处理

封装新的HttpService

实现的基本思路是新建一个自己的Service来处理http请求,在此Service中对requestresponse进行统一的处理后再调用Angular提供的HttpModule来对后端数据接口发起请求。
具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
export class MyHttpService{
constructor(private http:Http){}
get(url:string,reqOpts?:RequestOptionsArgs){
return this.request(url,Object.assign({
method:'get'
},reqOpts))
}
post(url:string,body: any,reqOpts?:RequestOptionsArgs){
return this.request(url,Object.assign({
method:'post',
},reqOpts),body)
}
put(url:string,body: any,reqOpts?:RequestOptionsArgs){
return this.request(url,Object.assign({
method:'put'
},reqOpts),body)
}
delete(url:string,reqOpts?:RequestOptionsArgs){
return this.request(url,Object.assign({
method:'delete'
},reqOpts))
}
request(url:string,reqOpts:RequestOptionsArgs,body?:any){
if (!reqOpts.headers){
reqOpts.headers=new Headers;
//统一指定Content-Type
reqOpts.headers.append('Content-Type','application/json')
}
if (!reqOpts.headers || reqOpts.headers.get('name')==null && reqOpts.headers.get('pass')==null){
//此处加入自己前端缓存的用户名和密码
}
if (body){
reqOpts.body=body;
}
return this.http.request(url,reqOpts)
}
}

在appModule中提供服务

1
providers: [MyHttpService]

然后只需要把原来注入Http的地方替换成MyHttpService就行了,嗯‘只要’……‘就行了’……