jQuery AJAX 完整封装教程:告别重复写请求代码
在前端项目中,如果你还在每个页面里反复写 $.ajax({ ... }),不仅代码冗余,而且后期维护极其痛苦:接口地址改了要全局替换、loading 逻辑到处复制、错误处理各写各的......
本文将带你从 基础封装 → 统一配置 → 拦截器 → 业务适配 ,一步步打造一个可复用、可维护、可扩展的 jQuery AJAX 请求层。
一、为什么要封装 AJAX?
先看一段"裸写"的 AJAX 代码:
javascript
$.ajax({
url: '/api/user/info',
type: 'GET',
dataType: 'json',
beforeSend: function () {
$('#loading').show();
},
success: function (res) {
$('#loading').hide();
if (res.code === 0) {
console.log(res.data);
} else {
alert(res.msg);
}
},
error: function () {
$('#loading').hide();
alert('网络错误');
}
});
问题显而易见:
- 重复代码极多(loading、错误处理)
- 接口地址分散,难以管理
- 响应格式不统一
- 无法统一做登录失效、权限校验
✅ 封装的目标:
- 统一请求 / 响应处理
- 自动携带 token
- 统一 loading、错误提示
- 接口集中管理
- 方便后期替换为 Fetch / Axios
二、最基础的封装:提取公共配置
1️⃣ 基础版本(适合小项目)
javascript
function request(options) {
const defaults = {
type: 'GET',
dataType: 'json',
timeout: 10000,
beforeSend() {
console.log('请求开始');
},
error(xhr, status) {
console.error('请求失败:', status);
}
};
const settings = $.extend(true, {}, defaults, options);
return $.ajax(settings);
}
使用方式:
javascript
request({
url: '/api/user/info',
success(res) {
console.log(res);
}
});
✅ 优点:简单直接
❌ 缺点:loading、token、错误处理仍不够统一
三、进阶封装:统一拦截器思想
我们模仿 Axios 的 请求拦截器 / 响应拦截器 思想。
2️⃣ 请求拦截器(统一加 token、loading)
javascript
function request(options) {
const token = localStorage.getItem('token');
const defaults = {
type: 'GET',
dataType: 'json',
timeout: 10000,
headers: {
Authorization: token ? `Bearer ${token}` : ''
},
beforeSend(xhr) {
// 显示 loading
window.loading && window.loading.show();
}
};
return $.ajax($.extend(true, {}, defaults, options));
}
3️⃣ 响应拦截器(统一处理返回数据)
假设后端返回格式统一为:
css
{
"code": 0,
"data": {},
"msg": "success"
}
封装响应处理:
javascript
function request(options) {
const token = localStorage.getItem('token');
const defaults = {
type: 'GET',
dataType: 'json',
timeout: 10000,
headers: {
Authorization: token ? `Bearer ${token}` : ''
},
beforeSend() {
window.loading && window.loading.show();
}
};
return $.ajax($.extend(true, {}, defaults, options))
.then(res => {
window.loading && window.loading.hide();
if (res.code === 0) {
return res.data; // 直接返回业务数据
}
// 业务错误
return Promise.reject(res.msg);
})
.catch(err => {
window.loading && window.loading.hide();
if (typeof err === 'string') {
alert(err);
} else {
alert('网络异常,请稍后重试');
}
return Promise.reject(err);
});
}
✅ 调用方只关心业务数据:
ini
request({
url: '/api/user/info'
}).then(data => {
console.log(data);
});
四、接口集中管理(强烈推荐)
4️⃣ 建立 api.js
css
// api.js
const API = {
getUserInfo: () => request({ url: '/api/user/info' }),
login: data => request({ url: '/api/login', type: 'POST', data }),
getOrderList: params => request({ url: '/api/orders', data: params })
};
页面中使用:
ini
API.getUserInfo().then(data => {
$('#username').text(data.name);
});
✅ 好处:
- 接口地址集中管理
- 页面代码更干净
- 后端接口变更,只改一处
五、登录失效 & 权限统一处理
5️⃣ 统一处理 401 / 403
ini
.catch(err => {
window.loading && window.loading.hide();
if (err.status === 401) {
alert('登录已过期,请重新登录');
location.href = '/login';
return;
}
if (typeof err === 'string') {
alert(err);
} else {
alert('请求失败');
}
return Promise.reject(err);
});
六、支持 GET / POST / PUT / DELETE 快捷方法
6️⃣ 封装常用方法
kotlin
const http = {
get(url, params) {
return request({ url, type: 'GET', data: params });
},
post(url, data) {
return request({ url, type: 'POST', data });
},
put(url, data) {
return request({ url, type: 'PUT', data });
},
delete(url, params) {
return request({ url, type: 'DELETE', data: params });
}
};
使用:
kotlin
http.get('/api/user/info').then(data => {
console.log(data);
});
http.post('/api/login', {
username: 'admin',
password: '123456'
});
七、完整最终版封装(推荐直接复制)
javascript
// request.js
function request(options) {
const token = localStorage.getItem('token');
const defaults = {
type: 'GET',
dataType: 'json',
timeout: 10000,
headers: {
Authorization: token ? `Bearer ${token}` : ''
},
beforeSend() {
window.loading && window.loading.show();
}
};
return $.ajax($.extend(true, {}, defaults, options))
.then(res => {
window.loading && window.loading.hide();
if (res.code === 0) {
return res.data;
}
return Promise.reject(res.msg);
})
.catch(err => {
window.loading && window.loading.hide();
if (err && err.status === 401) {
alert('登录失效,请重新登录');
location.href = '/login';
return;
}
if (typeof err === 'string') {
alert(err);
} else {
alert('网络异常,请稍后重试');
}
return Promise.reject(err);
});
}
const http = {
get(url, params) {
return request({ url, type: 'GET', data: params });
},
post(url, data) {
return request({ url, type: 'POST', data });
},
put(url, data) {
return request({ url, type: 'PUT', data });
},
delete(url, params) {
return request({ url, type: 'DELETE', data: params });
}
};
八、封装后的最佳实践总结
✅ **页面中不再出现 $.ajax**
✅ **所有接口集中在 api.js**
✅ 统一 token、loading、错误处理
✅ 后期可无缝迁移到 Axios / Fetch
九、常见扩展思路
- ✅ 接口缓存(GET 请求)
- ✅ 请求重试机制
- ✅ 多语言错误提示
- ✅ 多 token(普通 / 刷新 token)
- ✅ Mock 数据支持
十、结语
jQuery 虽"老",但在存量项目中依然广泛存在。
好的封装不是炫技,而是让团队少踩坑、多写业务代码。