Ajax基础使用详解
什么是Ajax?
AJAX(Asynchronous JavaScript and XML,异步JavaScript和XML)是一种在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术。
核心对象:XMLHttpRequest
1. 创建XMLHttpRequest对象
// 兼容不同浏览器
function createXHR() {
if (window.XMLHttpRequest) {
// 现代浏览器
return new XMLHttpRequest();
} else {
// 旧版IE
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
// 简单创建方式
let xhr = new XMLHttpRequest();
2. 基本请求流程
// 1. 创建对象
let xhr = new XMLHttpRequest();
// 2. 配置请求
xhr.open(method, url, async);
// method: GET, POST, PUT, DELETE等
// url: 请求地址
// async: 是否异步(默认true)
// 3. 设置请求头(可选)
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Authorization', 'Bearer token123');
// 4. 设置响应类型(可选)
xhr.responseType = 'json'; // 可设为 'text', 'json', 'blob', 'document'等
// 5. 发送请求
xhr.send(data); // GET请求时参数可为null或省略
// 6. 处理响应
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 请求成功
console.log(xhr.responseText);
} else {
// 请求失败
console.error('请求失败:', xhr.status);
}
}
};
readyState状态值
- 0: 请求未初始化(未调用open())
- 1: 服务器连接已建立(已调用open(),未调用send())
- 2: 请求已接收(已调用send(),收到响应头)
- 3: 请求处理中(下载响应体)
- 4: 请求完成,响应就绪
完整示例
GET请求示例
function getData() {
const xhr = new XMLHttpRequest();
const url = 'https://api.example.com/data';
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
// 成功
const data = JSON.parse(xhr.responseText);
console.log('获取的数据:', data);
updateUI(data);
} else {
// 失败
console.error('请求失败,状态码:', xhr.status);
}
}
};
xhr.onerror = function() {
console.error('网络错误');
};
xhr.send();
}
POST请求示例
function postData(userData) {
const xhr = new XMLHttpRequest();
const url = 'https://api.example.com/users';
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
const response = JSON.parse(xhr.responseText);
console.log('创建成功:', response);
} else {
console.error('创建失败:', xhr.status);
}
};
xhr.onerror = function() {
console.error('网络错误');
};
// 发送JSON数据
xhr.send(JSON.stringify(userData));
}
// 使用示例
postData({
name: '张三',
email: 'zhangsan@example.com'
});
使用Promise封装
function ajax(options) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const { method, url, data, headers = {} } = options;
xhr.open(method, url, true);
// 设置请求头
Object.keys(headers).forEach(key => {
xhr.setRequestHeader(key, headers[key]);
});
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const response = xhr.responseType === 'json'
? xhr.response
: JSON.parse(xhr.responseText);
resolve(response);
} catch (e) {
resolve(xhr.responseText);
}
} else {
reject(new Error(`请求失败: ${xhr.status}`));
}
};
xhr.onerror = function() {
reject(new Error('网络错误'));
};
xhr.ontimeout = function() {
reject(new Error('请求超时'));
};
// 发送请求
if (method === 'GET' || !data) {
xhr.send();
} else if (data instanceof FormData) {
xhr.send(data);
} else {
xhr.send(JSON.stringify(data));
}
});
}
// 使用示例
ajax({
method: 'GET',
url: 'https://api.example.com/data',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
}
})
.then(data => console.log(data))
.catch(error => console.error(error));
处理不同响应类型
// JSON响应
xhr.responseType = 'json';
xhr.onload = function() {
const data = xhr.response; // 直接获取JSON对象
};
// XML响应
xhr.responseType = 'document';
xhr.onload = function() {
const xmlDoc = xhr.responseXML;
const items = xmlDoc.getElementsByTagName('item');
};
// Blob响应(如下载文件)
xhr.responseType = 'blob';
xhr.onload = function() {
const blob = xhr.response;
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'file.pdf';
a.click();
URL.revokeObjectURL(url);
};
设置超时和进度
function uploadFile(file) {
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('file', file);
xhr.open('POST', '/upload', true);
// 设置超时(毫秒)
xhr.timeout = 30000;
// 上传进度
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
console.log(`上传进度: ${percentComplete.toFixed(2)}%`);
updateProgressBar(percentComplete);
}
};
// 下载进度
xhr.onprogress = function(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
console.log(`下载进度: ${percentComplete.toFixed(2)}%`);
}
};
xhr.onload = function() {
if (xhr.status === 200) {
console.log('上传成功');
}
};
xhr.ontimeout = function() {
console.error('请求超时');
};
xhr.send(formData);
}
跨域请求处理
// 1. 服务器需要设置CORS头
// Access-Control-Allow-Origin: *
// Access-Control-Allow-Methods: GET, POST, PUT, DELETE
// Access-Control-Allow-Headers: Content-Type, Authorization
// 2. 带凭据的请求
xhr.withCredentials = true;
// 3. 预检请求(OPTIONS)
// 复杂请求会自动发送预检请求
实际应用示例
// 完整的API工具类
class ApiClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.defaultHeaders = {
'Content-Type': 'application/json',
};
}
setToken(token) {
this.defaultHeaders['Authorization'] = `Bearer ${token}`;
}
request(endpoint, options = {}) {
const { method = 'GET', data, headers = {} } = options;
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const url = `${this.baseUrl}${endpoint}`;
xhr.open(method, url, true);
// 合并请求头
const allHeaders = { ...this.defaultHeaders, ...headers };
Object.keys(allHeaders).forEach(key => {
xhr.setRequestHeader(key, allHeaders[key]);
});
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const response = JSON.parse(xhr.responseText);
resolve(response);
} catch (e) {
resolve(xhr.responseText);
}
} else {
reject({
status: xhr.status,
message: xhr.statusText,
data: xhr.responseText
});
}
};
xhr.onerror = () => reject(new Error('网络错误'));
xhr.send(data ? JSON.stringify(data) : null);
});
}
get(endpoint, params) {
const query = params ? `?${new URLSearchParams(params)}` : '';
return this.request(`${endpoint}${query}`);
}
post(endpoint, data) {
return this.request(endpoint, { method: 'POST', data });
}
put(endpoint, data) {
return this.request(endpoint, { method: 'PUT', data });
}
delete(endpoint) {
return this.request(endpoint, { method: 'DELETE' });
}
}
// 使用示例
const api = new ApiClient('https://api.example.com');
// 获取用户列表
api.get('/users')
.then(users => console.log(users))
.catch(error => console.error(error));
// 创建新用户
api.post('/users', { name: '李四', age: 25 })
.then(user => console.log('创建的用户:', user));
注意事项
同源策略: Ajax请求受同源策略限制,跨域请求需要服务器支持CORS
异步性: Ajax默认是异步的,注意回调函数的执行时机
错误处理: 始终处理错误情况(网络错误、服务器错误等)
内存泄漏: 长时间未响应的请求要及时中止
兼容性: 考虑旧版浏览器兼容性
安全性: 避免敏感信息泄露,验证服务器响应
中止请求
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data', true);
xhr.send();
// 中止请求
xhr.abort();
// 检查是否已中止
if (xhr.readyState !== 4) {
console.log('请求已中止');
}
现代替代方案
虽然XMLHttpRequest是基础,但现代开发中更常用:
- Fetch API: 更现代、更强大的API
- axios: 基于Promise的HTTP客户端
- jQuery.ajax: jQuery提供的简化方法
Ajax是现代Web应用的基础,理解其原理和用法对于前端开发至关重要。