某商城前端架构总结与反思(http拦截器)

  • 邢毅彪
  • 18 Minutes
  • 2018年6月28日

前言

前后端分离项目中, 无论是登录鉴权, 还是与restful接口交互,离不开http拦截器。而axios和angular中的http包均提供了对http拦截器很好的支持

实施

首先参考文档axios, angular/http
商城项目具体实现代码(axios)

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import axios from 'axios'
import vm from '../main'

import * as qs from 'qs'
// const qs = require('qs')

export const DefaultPostAxios = axios.create()

let token:string = localStorage.getItem('token') || ''

// 设置默认请求头
axios.defaults.headers.common.QZH_TOKEN = token
DefaultPostAxios.defaults.headers.common.QZH_TOKEN = token

// 全局设置post请求
axios.interceptors.request.use((config) => {
const { data, method } = config
if (method.toLocaleLowerCase() === 'post') {
config.data = qs.stringify(data)
}
return config
}, (error) => Promise.reject(error))

// 全局拦截token失效
axios.interceptors.response.use((res) => {
const { status, msg } = res.data
const { NODE_ENV } = process.env
// 如果token失效
if (status === 400 && NODE_ENV === 'production') {
location.href = `/login?from=${location.href}`
} else if (status === 200) {
Promise.resolve(res)
} else {
vm.$message.error(msg)
}
return res
}, error => {
Promise.reject(error)
vm.$message.error('网络错误,请稍后重试')
})

DefaultPostAxios.interceptors.response.use((res) => {
const { status, msg } = res.data
const { NODE_ENV } = process.env
// 如果token失效
if (status === 400 && NODE_ENV === 'production') {
location.href = '/login'
} else if (status === 200) {
Promise.resolve(res)
} else {
vm.$message.error(msg)
}
return res
}, error => {
Promise.reject(error)
vm.$message.error('网络错误,请稍后重试')
})

export default axios

angular实现

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
40
41
42
43
44
45
46
47
48
49
// set-token-header-interceptor.ts
import { Injectable } from '@angular/core'
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
HttpResponse,
} from '@angular/common/http'
import * as qs from 'qs'

import { Observable } from 'rxjs'
import { AuthServiceService } from '../serves/auth-service.service';
import { tap } from 'rxjs/operators';

@Injectable()
export class SetTokenHeaderInterceptor implements HttpInterceptor {
constructor(private auth: AuthServiceService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
const token = this.auth.getToken()
const { body, method, headers } = req
const customerHeaders = {
QZH_TOKEN: token,
'Content-Type': headers.get('Content-Type') || 'application/x-www-form-urlencoded'
}

const reqWithToken = req.clone({
setHeaders: customerHeaders,
body: method.toLocaleLowerCase() === 'post' || !headers.get('Content-Type') ? qs.stringify(body) : body
})

return next.handle(reqWithToken)
.pipe(
tap(
(event) => {
if (event instanceof HttpResponse) {
// console.log(event.body)
const { status } = event.body
switch(status) {
case 400:
location.href = '/admin/login'
break;
}
}
}
)
)
}
}

1
2
3
4
5
6
7
8
9
// http-interceptors/index.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http'

// 设置token请求头
import { SetTokenHeaderInterceptor } from './set-token-header-interceptor'

export const httpInterceptorProviders = [
{ provide: HTTP_INTERCEPTORS, useClass: SetTokenHeaderInterceptor, multi: true }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// app.module.ts
import { httpInterceptorProviders } from './http-interceptors';
@NgModule({
declarations: [
AppComponent,
],
imports: [
],
providers: [
httpInterceptorProviders,
],
bootstrap: [AppComponent]
})
export class AppModule { }
访问量