第 4 章 · jQuery Ajax 与数据交互
本章目标:掌握 $.ajax 完整参数、$.get / $.post / $.getJSON;对比 Fetch API;实现 加载状态与错误处理;在 Django 后台场景正确提交 CSRF Token;为 admin-demo 对接模拟商品列表接口。
学时建议:5~6 小时(含 2 小时跟练)
前置:jquery-layui ch01~ch03;frontend-web ch12(Fetch、async/await)。
4.1 $.ajax 完整参数
$.ajax({
url: '/api/admin/products/',
type: 'GET', // 或 method: 'GET'(1.9+)
data: { page: 1, size: 20, keyword: '示例' },
dataType: 'json', // 期望响应类型:json / html / text
timeout: 10000, // 毫秒
cache: false, // GET 防缓存
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
beforeSend: function (xhr) {
$('#product-tbody').addClass('is-loading');
},
success: function (data, textStatus, xhr) {
renderProductTable(data.results || data);
},
error: function (xhr, textStatus, errorThrown) {
var msg = xhr.responseJSON && xhr.responseJSON.message
? xhr.responseJSON.message
: '请求失败:' + xhr.status;
showToast(msg, 'error');
},
complete: function () {
$('#product-tbody').removeClass('is-loading');
}
});
| 参数 | 说明 |
|---|---|
url | 请求地址 |
type / method | HTTP 动词 |
data | 查询串或对象;对象默认 application/x-www-form-urlencoded |
contentType | 默认 application/x-www-form-urlencoded; charset=UTF-8 |
processData | 是否序列化 data;上传 FormData 时设 false |
dataType | 自动解析 json;设 json 时非法 JSON 走 error |
traditional | 数组序列化方式(与 Django 列表参数相关) |
4.2 简写方法
// GET
$.get('/api/admin/products/', { page: 1 }, function (data) {
console.log(data);
});
// POST
$.post('/api/admin/products/', { name: '新品', price: 99 }, function (res) {
console.log(res.id);
});
// 只取 JSON
$.getJSON('/api/admin/products/stats.json', function (stats) {
$('#stat-orders').text(stats.order_count);
});
| 方法 | 等价 |
|---|---|
$.get(url, data, success) | $.ajax GET |
$.post(url, data, success) | $.ajax POST |
$.getJSON(url, success) | GET + dataType: 'json' |
Promise 风格(jQuery 3+ 原生;1.12 可用 $.Deferred):
// 1.12 Deferred
var req = $.get('/api/admin/products/');
req.done(function (data) { /* ... */ });
req.fail(function (xhr) { /* ... */ });
4.3 与 Fetch 对比
| 维度 | jQuery $.ajax | Fetch |
|---|---|---|
| 浏览器支持 | 需引入 jQuery | 现代浏览器原生 |
| JSON 解析 | dataType: 'json' 自动 | 需 res.json() |
| 超时 | timeout 内置 | 需 AbortController |
| 进度 | xhr 对象 | 有限 |
| 错误 | HTTP 4xx/5xx 仍可能进 success(看 dataType) | res.ok 需手动判断 |
| 取消 | xhr.abort() | AbortController |
// Fetch(frontend-web ch12)
async function loadProductsFetch() {
const res = await fetch('/api/admin/products/?page=1');
if (!res.ok) throw new Error('HTTP ' + res.status);
return res.json();
}
// jQuery 等价
function loadProductsJq() {
return $.getJSON('/api/admin/products/', { page: 1 });
}
行业常见策略:存量 Layui / jQuery 页继续 $.ajax;新 Vue 模块用 axios / Fetch。维护老后台必须熟悉 $.ajax。
4.4 加载状态与错误处理
4.4.1 全局 Ajax 事件
$(document)
.ajaxStart(function () {
$('#global-loading').show();
})
.ajaxStop(function () {
$('#global-loading').hide();
})
.ajaxError(function (event, xhr, settings, thrown) {
console.error(settings.url, thrown);
});
| 全局事件 | 触发时机 |
|---|---|
ajaxStart / ajaxStop | 任意 Ajax 开始 / 全部结束 |
ajaxSend | 单个请求发送前 |
ajaxComplete | 单个请求完成(含失败) |
ajaxSuccess | 单个成功 |
ajaxError | 单个失败 |
4.4.2 统一封装(admin-demo)
var Api = {
request: function (options) {
var defaults = {
type: 'GET',
dataType: 'json',
timeout: 15000
};
var opts = $.extend({}, defaults, options);
return $.ajax(opts).then(
function (data) {
if (data && data.code !== undefined && data.code !== 0) {
return $.Deferred().reject(data).promise();
}
return data.data !== undefined ? data.data : data;
},
function (xhr) {
var body = xhr.responseJSON || {};
var message = body.message || '网络异常,请稍后重试';
showToast(message, 'error');
return $.Deferred().reject(xhr).promise();
}
);
},
getProducts: function (params) {
return this.request({ url: '/api/admin/products/', data: params });
}
};
响应约定(与常见 REST 封装对齐):
{
"code": 0,
"message": "ok",
"data": {
"results": [],
"total": 0
}
}
4.5 Django CSRF Token 提交
Django 对 POST/PUT/DELETE 等变更请求校验 CSRF。jQuery 需在请求头或表单字段携带 token。
4.5.1 从 Cookie 读取(推荐)
function getCookie(name) {
var match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'));
return match ? decodeURIComponent(match[1]) : null;
}
function csrfSafeMethod(method) {
return /^(GET|HEAD|OPTIONS|TRACE)$/.test(method);
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'));
}
}
});