1. JavaScript发送请求的核心方法解析
在现代Web开发中,JavaScript发送请求是与服务器交互的基础能力。从早期的XMLHttpRequest到现代的Fetch API,再到各种第三方库封装的方法,开发者有多种选择来实现网络通信。本文将深入剖析这些方法的实现原理、适用场景和实际应用技巧。
1.1 原生XMLHttpRequest对象
作为浏览器最早提供的异步通信接口,XMLHttpRequest(XHR)仍然是许多老项目的基础。它的核心使用模式如下:
javascript复制const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send();
关键点解析:
readyState的5个状态值(0-4)反映了请求的生命周期status属性需要结合HTTP状态码判断请求结果- 同步模式(第三个参数为false)会阻塞UI线程,应避免使用
实际开发中常见问题:
- 跨域请求需要服务器配置CORS头部
- 超时控制需要手动实现:
javascript复制xhr.timeout = 5000; // 5秒超时 xhr.ontimeout = function() { /* 处理逻辑 */ }; - 上传进度监控:
javascript复制xhr.upload.onprogress = function(e) { const percent = Math.round((e.loaded / e.total) * 100); };
1.2 Fetch API的现代化方案
Fetch API提供了更简洁的Promise-based接口,已成为现代开发的首选:
javascript复制fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) throw new Error('Network response was not ok');
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
进阶用法包括:
- 请求配置对象:
javascript复制fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer token' }, body: JSON.stringify(payload) }); - 取消请求使用AbortController:
javascript复制const controller = new AbortController(); fetch(url, { signal: controller.signal }); // 取消请求 controller.abort(); - 流式处理大响应:
javascript复制const response = await fetch(url); const reader = response.body.getReader(); while(true) { const { done, value } = await reader.read(); if (done) break; // 处理数据块 }
1.3 第三方库的封装方案
1.3.1 Axios的核心优势
Axios结合了XHR的可靠性和Promise的便利性:
javascript复制axios.get('/user', {
params: { ID: 12345 },
timeout: 5000
})
.then(response => console.log(response.data))
.catch(error => console.log(error));
独特功能包括:
- 自动转换JSON数据
- 客户端XSRF防护
- 拦截器机制:
javascript复制// 请求拦截器 axios.interceptors.request.use(config => { config.headers.Authorization = getToken(); return config; }); // 响应拦截器 axios.interceptors.response.use( response => response, error => { if (error.response.status === 401) { // 处理未授权 } return Promise.reject(error); } );
1.3.2 jQuery的$.ajax方法
虽然现代项目较少使用,但遗留系统中仍常见:
javascript复制$.ajax({
url: "test.html",
dataType: "json",
data: { key: "value" }
}).done(function(data) {
console.log("Data:", data);
});
特点包括:
- 自动处理回调地狱
- 丰富的扩展事件:
javascript复制.fail(function(jqXHR, textStatus, errorThrown) {}) .always(function() {})
1.4 WebSocket实时通信
对于需要持久连接的场景:
javascript复制const socket = new WebSocket('wss://echo.websocket.org');
socket.onopen = function(e) {
socket.send('Hello Server!');
};
socket.onmessage = function(event) {
console.log('Received:', event.data);
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log('Clean connection closure');
} else {
console.log('Connection died');
}
};
关键考虑因素:
- 心跳机制保持连接活跃
- 消息序列化协议选择(JSON/Protobuf等)
- 重连策略实现
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 高级应用场景与性能优化
2.1 请求竞速与缓存策略
javascript复制const fetchWithTimeout = (url, timeout = 8000) => {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
)
]);
};
缓存策略实现:
javascript复制const cachedFetch = async (url, options = {}) => {
const cacheKey = url + JSON.stringify(options);
// 检查sessionStorage缓存
const cached = sessionStorage.getItem(cacheKey);
if (cached) return JSON.parse(cached);
const response = await fetch(url, options);
const data = await response.json();
// 存储到缓存
sessionStorage.setItem(cacheKey, JSON.stringify(data));
return data;
};
2.2 批量请求与并发控制
使用Promise.all处理并行请求:
javascript复制const [user, posts] = await Promise.all([
fetch('/user'),
fetch('/posts')
]);
实现并发控制:
javascript复制async function parallelWithLimit(urls, limit = 3) {
const results = [];
const executing = [];
for (const url of urls) {
const p = fetch(url).then(r => r.json());
results.push(p);
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e);
if (executing.length >= limit) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
2.3 文件上传的进阶处理
分块上传实现:
javascript复制const chunkSize = 1024 * 1024; // 1MB
const file = input.files[0];
let offset = 0;
while (offset < file.size) {
const chunk = file.slice(offset, offset + chunkSize);
const formData = new FormData();
formData.append('file', chunk);
formData.append('offset', offset);
await fetch('/upload', {
method: 'POST',
body: formData
});
offset += chunkSize;
}
3. 安全实践与异常处理
3.1 常见安全防护措施
CSRF防护:
javascript复制// 从cookie中获取token
function getCSRFToken() {
return document.cookie.replace(
/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/,
'$1'
);
}
// 添加到请求头
axios.defaults.headers.common['X-XSRF-TOKEN'] = getCSRFToken();
敏感数据保护:
javascript复制// 使用加密库处理敏感参数
const encryptedData = CryptoJS.AES.encrypt(
JSON.stringify(data),
secretKey
).toString();
3.2 全面的错误处理方案
结构化错误处理:
javascript复制class APIError extends Error {
constructor(message, status, payload) {
super(message);
this.status = status;
this.payload = payload;
}
}
async function safeFetch(url, options) {
try {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new APIError(
error.message || 'Request failed',
response.status,
error
);
}
return response.json();
} catch (err) {
if (err instanceof TypeError) {
// 网络错误处理
throw new APIError('Network error', 0);
}
throw err;
}
}
3.3 性能监控与日志记录
请求耗时统计:
javascript复制const start = performance.now();
try {
await fetch(url);
const duration = performance.now() - start;
metrics.track('api_latency', duration);
} catch (err) {
// 错误记录
}
前端日志收集:
javascript复制window.addEventListener('unhandledrejection', event => {
if (event.reason instanceof APIError) {
logToServer({
type: 'api_error',
error: event.reason
});
}
});
4. 现代浏览器API与未来趋势
4.1 Beacon API的页面退出统计
javascript复制// 可靠地发送最终统计数据
window.addEventListener('unload', function() {
navigator.sendBeacon('/log', analyticsData);
});
4.2 Server-Sent Events的实时更新
javascript复制const eventSource = new EventSource('/updates');
eventSource.onmessage = function(event) {
console.log('New message:', event.data);
};
eventSource.addEventListener('stockUpdate', function(event) {
updateChart(JSON.parse(event.data));
});
4.3 HTTP/2与gRPC的应用
通过fetch使用二进制协议:
javascript复制const response = await fetch('/grpc-endpoint', {
method: 'POST',
headers: {
'Content-Type': 'application/grpc-web+proto'
},
body: binaryData
});
const binaryResponse = await response.arrayBuffer();
5. 调试技巧与工具链
5.1 Chrome开发者工具实战
网络面板高级用法:
- 过滤特定类型请求(XHR/Fetch/WS等)
- 节流设置模拟弱网环境
- 导出HAR文件分析性能瓶颈
控制台调试技巧:
javascript复制// 监控特定URL的请求
const originalFetch = window.fetch;
window.fetch = function(...args) {
console.log('Fetching:', args[0]);
return originalFetch.apply(this, args);
};
5.2 代理工具与Mock方案
本地开发Mock方案:
javascript复制// 使用Mock Service Worker
import { setupWorker, rest } from 'msw';
const worker = setupWorker(
rest.get('/user', (req, res, ctx) => {
return res(
ctx.delay(150),
ctx.json({ name: 'Mock User' })
);
})
);
worker.start();
5.3 性能分析工具链
Lighthouse审计要点:
- 减少未使用的JavaScript
- 消除渲染阻塞资源
- 适当预加载关键请求
WebPageTest瀑布图分析:
- 识别请求依赖链
- 发现未压缩的资源
- 检测DNS查询时间过长的问题
