在Web开发中,实现页面的局部更新和无刷新数据交互是提升用户体验的关键。AJAX(Asynchronous JavaScript and XML)作为一项核心技术,让这种交互成为可能。本文将深入讲解AJAX的原理、应用场景及实现方式。
一、AJAX基础概念
1.1 什么是AJAX
- AJAX全称:Asynchronous JavaScript and XML(异步的JavaScript和XML)
- 核心作用:实现浏览器和服务器的异步数据交互
- 特点:可以在不刷新整个页面的情况下,与服务器交换数据并更新部分网页内容
XMLHttpRequest实例的创建与使用
// 1. 标准创建方式
const xhr = new XMLHttpRequest();
// 2. 兼容性写法(适配IE5/6)
function createXHR() {
if (typeof XMLHttpRequest !== "undefined") {
return new XMLHttpRequest();
} else if (typeof ActiveXObject !== "undefined") {
// IE6及以下
if (typeof arguments.callee.activeXString !== "string") {
const versions = [
"MSXML2.XMLHttp.6.0",
"MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"
];
for (let i = 0; i < versions.length; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch(ex) {
// 跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available");
}
}
1.2 同步与异步的区别
同步:
- 代码按顺序执行
- 前一个任务完成后才能执行后一个任务
- 可能造成页面阻塞
异步:
- 多个任务可以同时执行
- 任务之间互不影响
- 提高页面性能和用户体验
// 同步示例
console.log('开始');
alert('同步操作');
console.log('结束');
// 异步示例
console.log('开始');
setTimeout(() => {
console.log('异步操作');
}, 1000);
console.log('结束');
二、AJAX状态码详解
2.1 readyState状态码
XMLHttpRequest对象的readyState属性表示请求/响应过程的当前活动阶段:
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch(xhr.readyState) {
case 0: // UNSENT
console.log('尚未调用open()方法');
break;
case 1: // OPENED
console.log('已调用open()方法');
break;
case 2: // HEADERS_RECEIVED
console.log('已接收响应头');
break;
case 3: // LOADING
console.log('正在接收响应体');
break;
case 4: // DONE
console.log('请求完成');
break;
}
};
2.2 HTTP状态码
常见的HTTP状态码及其含义:
- 2xx 成功响应
- 200:请求成功
- 201:创建成功
- 3xx 重定向
- 301:永久重定向
- 302:临时重定向
- 4xx 客户端错误
- 400:请求语法错误
- 404:资源不存在
- 5xx 服务器错误
- 500:服务器内部错误
2.3 XHR对象的属性
// 1. readyState - 请求/响应过程的当前活动阶段
xhr.readyState
// 0: 未初始化。尚未调用open()方法
// 1: 启动。已经调用open()方法,但未调用send()方法
// 2: 发送。已经调用send()方法,但尚未接收到响应
// 3: 接收。已经接收到部分响应数据
// 4: 完成。已经接收到全部响应数据
// 2. status - HTTP状态码
xhr.status // 如:200, 404, 500等
// 3. statusText - HTTP状态说明
xhr.statusText // 如:"OK", "Not Found"等
// 4. responseType - 响应数据类型
xhr.responseType // "text", "json", "blob", "arraybuffer"等
// 5. response - 响应内容
xhr.response
// 6. timeout - 超时时间设置(毫秒)
xhr.timeout = 3000;
2.4 核心方法使用
// 1. open() - 初始化请求
xhr.open("GET", "url", true); // method, url, async
// 第三个参数true表示异步请求,false表示同步请求
// 2. send() - 发送请求
xhr.send(null); // GET请求
xhr.send(data); // POST请求发送数据
// 3. setRequestHeader() - 设置请求头
xhr.setRequestHeader("Content-Type", "application/json");
// 4. abort() - 终止请求
xhr.abort();
AJAX请求默认是异步的,但确实可以配置为同步。这两种模式各有适用场景
异步请求(默认)
适用场景:
- 大多数情况下应该使用异步请求
- 需要保持用户界面响应性的情况
- 执行后台操作而不阻塞用户交互
- 多个并行请求需要同时进行
- 长时间运行的操作(如数据上传、大量数据处理)
优点:
- 不会阻塞用户界面
- 提供更好的用户体验
- 允许用户继续与页面交互
- 可以同时处理多个请求
同步请求(特殊情况)
适用场景:
- 当后续代码严格依赖于请求结果才能继续执行
- 需要确保按特定顺序执行的操作
- 加载关键配置数据,必须先完成才能继续
- 简单的脚本或原型开发,不关注用户体验
- 在注销或页面卸载前需要保证数据已发送到服务器
注意事项:
- 同步请求会完全阻塞浏览器界面
- 现代浏览器已经开始不推荐或禁用同步请求
- 会导致糟糕的用户体验,用户界面会冻结直到请求完成
最佳实践是尽可能使用异步请求,结合回调函数、Promise或async/await来处理请求完成后的逻辑,而不是使用同步请求。大多数现代浏览器已经不再推荐使用同步AJAX请求,并在控制台中发出警告。
2.5 事件处理
// 1. onreadystatechange - 请求状态变化事件
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
}
}
};
// 2. 其他常用事件
xhr.onload = function() {
// 请求完成时触发
};
xhr.onerror = function() {
// 请求错误时触发
};
xhr.ontimeout = function() {
// 请求超时时触发
};
xhr.onabort = function() {
// 请求终止时触发
};
xhr.onprogress = function(event) {
// 接收数据过程中周期性触发
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
console.log(percentComplete + '% completed');
}
};
2.6 完整使用示例
function ajax(options) {
const xhr = new XMLHttpRequest();
// 设置超时
xhr.timeout = options.timeout || 3000;
// 监听状态变化
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
options.success && options.success(xhr.responseText);
} else {
options.error && options.error(xhr.status);
}
}
};
// 监听错误
xhr.onerror = function() {
options.error && options.error();
};
// 监听超时
xhr.ontimeout = function() {
options.timeout && options.timeout();
};
// 处理请求参数
let url = options.url;
if (options.method.toUpperCase() === 'GET' && options.data) {
url += '?' + Object.entries(options.data)
.map(([key, value]) => `${key}=${value}`)
.join('&');
}
// 初始化请求
xhr.open(options.method, url, true);
// 设置请求头
if (options.headers) {
Object.entries(options.headers).forEach(([key, value]) => {
xhr.setRequestHeader(key, value);
});
}
// 发送请求
if (options.method.toUpperCase() === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(options.data));
} else {
xhr.send();
}
}
// 使用示例
ajax({
url: 'https://api.example.com/data',
method: 'POST',
data: {
name: 'test',
age: 18
},
headers: {
'Authorization': 'Bearer token'
},
success: function(res) {
console.log('请求成功:', res);
},
error: function(status) {
console.log('请求失败:', status);
},
timeout: function() {
console.log('请求超时');
}
});
三、GET与POST请求详解
3.1 GET请求特点
- 用于获取数据
用于从服务器获取(拿取)数据
- 参数通过URL传递
在浏览器地址栏输入URL回车时,默认使用GET请求(通常用于查询操作)
- 有缓存
通过时间戳解决该问题
- 传数据量较小
const xhr = new XMLHttpRequest();
xhr.open('GET', 'api/data?id=123&name=test', true);
// 解决GET请求缓存问题
xhr.open('GET', `api/data?t=${new Date().getTime()}`, true);
xhr.send();
基本格式说明:
- ? - 问号后面开始是 URL 参数
- 参数=值 - 每个参数都是 "参数名=参数值" 的格式
- & - 使用 & 符号分隔多个参数
https://example.com/path?参数1=值1&参数2=值2&参数3=值3
3.2 POST请求特点
- 用于提交数据
- 参数通过请求体传递
用于向服务器提交(发送)数据,多与表单提交场景搭配,通常用于创建或更新操作
- 无缓存
- 可传输大量数据
- 相对更安全
const xhr = new XMLHttpRequest();
xhr.open('POST', 'api/data', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({id: 123, name: 'test'}));
AJAX请求主要使用的是HTTP请求方法,HTTP协议定义的标准请求方法只有9种
GET、POST、PUT、DELETE、HEAD、OPTIONS、PATCH、CONNECT、TRACE
比较常见的 6 种请求方式:
- GET - 用于从服务器获取数据,参数通常附加在URL后面
- POST - 用于向服务器发送数据以创建或更新资源,数据包含在请求体中
- PUT - 用于更新服务器上的现有资源,发送完整的资源数据
- DELETE - 用于删除服务器上的指定资源
- PATCH - 用于对资源进行部分更新,只发送需要修改的部分
- HEAD - 类似于GET请求但只请求头信息,不返回响应体
具体用什么请求方式,由后端决定,后端会写一个接口文档给前端
四、接口(API)概念
接口是只返回数据而没有界面的URL地址,英文叫api(Application Programming Interface)
输入网址能在页面上显示数据的都为接口地址,简称接口
接口链接示例: https://jsonplaceholder.typicode.com/users
复制到浏览器地址栏并回车即可查看接口数据
五、API接口文档示例
一个标准的接口文档应有的内容如下
基本信息 | 说明 |
---|---|
接口名称 | 用户登录 |
接口描述 | 用户通过账号密码进行登录认证 |
接口URL | /api/v1/user/login |
请求方式 | POST |
开发者 | 张三 |
创建时间 | 2024-02-22 |
更新时间 | 2024-02-22 |
请求头(Headers) | 是否必须 | 示例值 | 说明 |
---|---|---|---|
Content-Type | 是 | application/json | 请求类型 |
Authorization | 否 | Bearer eyJhbGciOi... | 登录凭证 |
x-client-id | 是 | web | 客户端标识 |
请求参数(Request Body) | 类型 | 是否必须 | 示例值 | 说明 |
---|---|---|---|---|
username | string | 是 | zhangsan | 用户名 |
password | string | 是 | md5(123456) | MD5加密后的密码 |
captcha | string | 否 | a1b2c | 验证码 |
remember | boolean | 否 | true | 是否记住登录 |
响应参数(Response) | 类型 | 说明 | 示例值 |
---|---|---|---|
code | number | 响应码 | 200 |
message | string | 响应描述 | "登录成功" |
data.userId | string | 用户ID | "12345" |
data.username | string | 用户名称 | "张三" |
data.token | string | 访问令牌 | "eyJhbGciOi..." |
data.permissions | array | 权限列表 | ["user:read"] |
响应状态码 | 说明 | 处理建议 |
---|---|---|
200 | 请求成功 | - |
400 | 参数错误 | 检查请求参数 |
401 | 未授权 | 检查登录状态 |
403 | 权限不足 | 检查用户权限 |
500 | 服务器错误 | 联系后端开发 |
5.1 请求示例
后端接口需要的参数
{
"username": "zhangsan",
"password": "e10adc3949ba59abbe56e057f20f883e",
"captcha": "a1b2c",
"remember": true
}
5.2 响应示例
后端返回的数据
{
"code": 200,
"message": "登录成功",
"data": {
"userId": "12345",
"username": "张三",
"token": "eyJhbGciOi...",
"permissions": ["user:read", "user:write"]
}
}
5.2 失败响应示例
接口因为某些原因没请求成功
{
"code": 401,
"message": "用户名或密码错误",
"data": null
}
补充说明 | 内容 |
---|---|
请求限制 | 接口调用频率:10次/分钟 |
安全要求 | 密码需MD5加密,必须使用HTTPS |
特殊说明 | Token有效期为2小时 |
修改记录 | |
---|---|
修改人 | 张三 |
修改时间 | 2024-02-22 |
修改内容 | 创建接口文档 |
AJAX与接口文档知识总结
核心知识点回顾
- AJAX三大核心
- XMLHttpRequest对象的创建和使用
- GET/POST请求的区别和应用场景
- 异步处理机制和状态码判断
- 接口规范要点
- 标准的接口文档结构(基本信息、请求参数、响应格式)
- 接口安全性考虑(请求头、鉴权方式)
- 错误处理机制
实际应用建议
- 开发实践
- AJAX请求建议封装统一处理函数
- 善用Promise处理异步请求
- 合理使用GET/POST:查询用GET,提交用POST
- 文档规范
- 使用统一的文档模板
- 保持文档及时更新
- 示例代码必须完整可用
重点注意事项
- AJAX使用注意
- 处理好跨域问题
- 注意GET请求的缓存问题
- 异常处理不可遗漏
- 接口文档维护
- 参数说明要清晰完整
- 及时更新接口变更
- 做好版本控制
学习建议
- 多写demo加深理解
- 实际项目中注意积累经验
- 推荐使用成熟的请求库(如Axios)
- 熟练使用接口文档工具(如Swagger)
通过掌握AJAX和规范的接口文档写法,我们能更好地进行前后端协作,提高开发效率。在实际工作中,应当注重实践和积累,不断提升自己的专业能力。
从原生AJAX到Axios
知识衔接说明
- 学习路径
- 学习原生AJAX是为了理解底层原理
- Axios是在AJAX基础上的封装优化
- 实际开发中推荐使用 Axios
- Axios的优势
- 更简洁的API设计
- 自动转换JSON数据
- 客户端支持防御XSRF
- 请求和响应的拦截器
- 更好的异常处理机制
官网说明
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
实际开发建议
// 原生AJAX写法(学习理解原理)
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/users');
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send();
// Axios写法(实际开发使用)
axios.get('/api/users')
.then(response => console.log(response.data))
.catch(error => console.log(error));
学习建议
- 先掌握AJAX原理,理解异步请求的本质
- 再学习Axios,提高开发效率
- 实际项目中使用Axios,遇到问题能追溯到AJAX层面解决
记住:学习原生AJAX是为了理解原理,而在实际工作中,Axios等成熟的HTTP客户端库才是首选。这样既掌握了基础原理,又能提高开发效率。
博主另一篇文章有对 axios 请求库的介绍:感兴趣可以看看
前后端是如何配合的 博主另一篇文档