vue封装请求拦截器 响应拦截器
在 Vue 项目中封装请求拦截器和响应拦截器通常使用 Axios 库。以下是一个完整的封装示例,包含基础配置、拦截器实现和错误处理:
### 第一步:安装 Axios
```bash
npm install axios
```
### 第二步:创建封装文件 `src/utils/request.js`
```javascript
import axios from 'axios'
import { Message } from 'element-ui' // 按需引入 UI 框架提示组件
import router from '@/router' // 引入路由实例
// 创建 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // 从环境变量读取基础 URL
timeout: 10000, // 请求超时时间
headers: { 'Content-Type': 'application/json;charset=UTF-8' }
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 在发送请求之前做些什么(例如添加 token)
const token = localStorage.getItem('token')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
// 可添加全局 loading 控制
// showLoading()
return config
},
error => {
// 对请求错误做些什么
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
// 隐藏全局 loading
// hideLoading()
// 处理二进制数据
if (response.config.responseType === 'blob') {
return response.data
}
const res = response.data
// 根据后端约定判断业务状态码
if (res.code !== 200) {
// 处理特殊状态码(如 token 过期)
if (res.code === 401) {
Message.error('登录已过期,请重新登录')
router.push('/login')
return Promise.reject(new Error('未授权'))
}
// 显示错误提示(可配置不显示特定状态码)
if (!response.config.noShowError) {
Message.error(res.message || '请求失败')
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
// 返回核心数据
return res.data
}
},
error => {
// 隐藏全局 loading
// hideLoading()
// 处理 HTTP 状态码错误
if (error.response) {
switch (error.response.status) {
case 400:
error.message = '请求错误'
break
case 401:
error.message = '未授权,请登录'
router.replace('/login')
break
case 403:
error.message = '拒绝访问'
break
case 404:
error.message = `请求地址出错: ${error.response.config.url}`
break
case 500:
error.message = '服务器内部错误'
break
default:
error.message = `连接错误 ${error.response.status}`
}
} else if (error.message.includes('timeout')) {
error.message = '请求超时,请检查网络'
} else {
error.message = '网络连接异常'
}
Message.error(error.message)
return Promise.reject(error)
}
)
/**
* 封装通用请求方法
* @param {Object} config 请求配置
*/
export function request(config) {
return service(config)
}
/**
* 封装 GET 请求
* @param {String} url
* @param {Object} params
* @param {Object} options 额外配置
*/
export function get(url, params = {}, options = {}) {
return service({
url,
method: 'get',
params,
...options
})
}
/**
* 封装 POST 请求
* @param {String} url
* @param {Object} data
* @param {Object} options 额外配置
*/
export function post(url, data = {}, options = {}) {
return service({
url,
method: 'post',
data,
...options
})
}
// 导出其他常用方法
export default {
request,
get,
post,
put: (url, data) => service({ url, method: 'put', data }),
delete: url => service({ url, method: 'delete' })
}
```
### 第三步:在 Vue 中全局引入(可选)
`src/main.js`
```javascript
import Vue from 'vue'
import request from '@/utils/request'
Vue.prototype.$http = request // 组件内使用 this.$http.get(...)
```
### 第四步:在组件中使用
```vue
<script>
import { get, post } from '@/utils/request'
export default {
methods: {
// GET 请求示例
async fetchData() {
try {
const res = await get('/api/user/list', {
page: 1,
size: 20
}, {
noShowError: true // 可选:禁止自动显示错误
})
console.log('数据获取成功', res)
} catch (err) {
console.error('请求失败', err)
}
},
// POST 请求示例
async submitForm() {
const data = { username: 'admin', password: '123456' }
const res = await post('/api/login', data)
console.log('登录结果', res)
},
// 使用全局注入方式
async deleteItem() {
const res = await this.$http.delete('/api/item/123')
console.log('删除结果', res)
}
}
}
</script>
```
### 关键功能说明:
1. **请求拦截器**:
- 自动添加 JWT 认证 Token
- 统一设置 Content-Type
- 全局 Loading 控制点(需自行实现)
2. **响应拦截器**:
- 处理二进制响应数据
- 统一处理业务错误码(如 401 跳转登录)
- 捕获 HTTP 状态码错误
- 网络异常处理(超时/断网)
3. **灵活配置**:
- `noShowError` 参数:禁止自动错误提示
- 环境变量管理 API 地址
- 支持特殊响应类型(如 blob)
4. **错误处理**:
- 分类处理网络错误/业务错误
- 自动显示友好错误提示
- 401 自动跳转登录页
### 最佳实践建议:
1. **环境配置**:在 `.env.development` 和 `.env.production` 中配置不同的 `VUE_APP_BASE_API`
2. **错误处理**:可在拦截器中添加错误日志上报
3. **重试机制**:可在响应拦截器中添加请求重试逻辑
4. **取消请求**:添加请求取消功能(使用 axios CancelToken)
5. **文件上传**:单独封装上传方法,处理进度事件
通过这种封装方式,可以实现:
- 统一处理认证逻辑
- 减少重复代码
- 集中管理 API 错误
- 增强请求的可控性
- 快速适配后端接口变更