前端开发实践:优雅封装JSON数据请求接口**
在现代前端开发中,与后端API进行数据交互是必不可少的一环,直接在各个组件或业务逻辑中编写fetch或axios请求代码,不仅会导致代码重复、难以维护,还可能引发一致性问题(如错误处理、请求头设置等),封装一套统一、健壮、易用的JSON数据请求接口,是提升前端项目质量和开发效率的关键实践,本文将详细介绍如何在前端项目中封装JSON数据请求接口。
为什么要封装JSON请求接口?
在探讨如何封装之前,我们先明确封装的必要性:
- 代码复用与DRY原则:避免在多处重复编写相似的请求逻辑。
- 统一管理:统一的API基础路径、请求头、错误处理等,便于维护和修改。
- 提升可维护性:当API发生变化(如URL前缀调整、认证方式变更)时,只需修改封装层,而不涉及业务代码。
- 增强健壮性:可以统一处理网络错误、HTTP状态码、数据格式校验、超时等异常情况。
- 便于扩展:可以轻松添加新功能,如请求/响应拦截器、取消请求、缓存策略等。
- 提升开发效率:业务开发者只需关注调用接口和数据处理,无需关心底层请求细节。
选择请求库:Fetch API vs. Axios
前端发送HTTP请求主要有两种选择:
- Fetch API:浏览器原生API,基于Promise,轻量级,但默认不处理错误(如404不会reject),不支持请求/响应拦截,配置相对简单。
- Axios:基于Promise的第三方库,功能更完善,自动转换JSON数据,支持请求/响应拦截器,支持取消请求,支持浏览器和Node.js环境,有更丰富的错误处理机制。
推荐选择:对于大多数项目,Axios是更优的选择,其强大的拦截器功能和完善的错误处理机制能极大简化封装工作,本文将以Axios为例进行讲解。
封装步骤详解
基础配置与实例创建
安装Axios:
npm install axios # 或 yarn add axios
创建一个Axios实例,并进行基础配置:
// src/utils/request.js
import axios from 'axios';
// 创建axios实例
const service = axios.create({
baseURL: 'https://api.example.com', // API的基础URL,可根据环境变量配置
timeout: 10000, // 请求超时时间
headers: {
'Content-Type': 'application/json', // 默认请求头
},
});
// 可以根据需要添加更多的默认配置
// service.defaults.withCredentials = true; // 跨域请求时是否需要凭证
请求拦截器
请求拦截器可以在请求发送前对请求进行统一处理,
- 添加统一的认证token(如Authorization头)
- 修改请求数据格式
- 请求发送前的日志记录
// 添加请求拦截器
service.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
const token = localStorage.getItem('token'); // 从本地存储获取token
if (token) {
config.headers['Authorization'] = `Bearer ${token}`; // 设置认证头
}
// 可以在这里对config进行修改,比如序列化data等
// config.data = JSON.stringify(config.data);
console.log('Request config:', config);
return config;
},
(error) => {
// 对请求错误做些什么
console.error('Request error:', error);
return Promise.reject(error);
}
);
响应拦截器
响应拦截器可以在收到响应后对响应进行统一处理,
- 统一处理HTTP状态码(如200, 401, 403, 404, 500等)
- 从响应数据中提取业务数据(如从
response.data.data中获取) - 统一错误处理(如token过期、服务器错误等)
// 添加响应拦截器
service.interceptors.response.use(
(response) => {
// 对响应数据做点什么
// 假设后端返回格式为 { code: 200, data: {}, message: 'success' }
const res = response.data;
// 根据后端返回的code字段判断请求是否成功
if (res.code === 200) {
return res.data; // 直接返回业务数据
} else {
// 业务逻辑错误,如code为400, 500等
// 可以在这里统一处理错误,比如弹窗提示
console.error('Business error:', res.message);
// 这里可以抛出一个自定义错误,让调用方处理
return Promise.reject(new Error(res.message || '请求失败'));
}
},
(error) => {
// 对响应错误做点什么
if (error.response) {
// 请求已发出,服务器返回状态码不在 2xx 范围内
const status = error.response.status;
switch (status) {
case 401:
// 未授权,可能是token过期,需要重新登录
console.error('Unauthorized, please login again.');
// 可以在这里触发登出逻辑,跳转到登录页
break;
case 403:
console.error('Forbidden');
break;
case 404:
console.error('Not Found');
break;
case 500:
console.error('Internal Server Error');
break;
default:
console.error(`Request error with status ${status}`);
}
} else if (error.request) {
// 请求已发出,但没有收到响应
console.error('No response received:', error.request);
} else {
// 在设置请求时发生错误
console.error('Request setup error:', error.message);
}
return Promise.reject(error);
}
);
封装具体的请求方法
为了方便调用,我们可以将常用的HTTP方法(GET, POST, PUT, DELETE等)封装成独立的函数,这些函数接收URL路径、请求数据、配置项等参数。
/**
* GET请求
* @param {string} url - 请求地址
* @param {object} params - 请求参数
* @param {object} config - 额外配置
* @returns {Promise} - 返回Promise对象
*/
export function get(url, params = {}, config = {}) {
return service({
method: 'get',
url,
params, // GET请求参数会自动拼接到URL后面
...config,
});
}
/**
* POST请求
* @param {string} url - 请求地址
* @param {object} data - 请求数据
* @param {object} config - 额外配置
* @returns {Promise} - 返回Promise对象
*/
export function post(url, data = {}, config = {}) {
return service({
method: 'post',
url,
data, // POST请求数据放在data中
...config,
});
}
/**
* PUT请求
* @param {string} url - 请求地址
* @param {object} data - 请求数据
* @param {object} config - 额外配置
* @returns {Promise} - 返回Promise对象
*/
export function put(url, data = {}, config = {}) {
return service({
method: 'put',
url,
data,
...config,
});
}
/**
* DELETE请求
* @param {string} url - 请求地址
* @param {object} params - 请求参数
* @param {object} config - 额外配置
* @returns {Promise} - 返回Promise对象
*/
export function del(url, params = {}, config = {}) {
return service({
method: 'delete',
url,
params,
...config,
});
}
// 可以根据需要封装PATCH等其他方法
导出封装后的请求方法
将封装好的请求方法导出,供项目其他模块使用。
// src/utils/request.js (完整版)
import axios from 'axios';
const service = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL || 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(response) => {
const res = response.data;
if (res.code === 200) {
return res.data;
} else {
// 可以根据


还没有评论,来说两句吧...