1. JS发送请求的全面解析与实战指南
在Web开发领域,JavaScript的请求发送能力是连接前端与后端的核心桥梁。从早期的XMLHttpRequest到现代的Fetch API,再到各种第三方库的封装,JS的请求发送方式已经形成了完整的生态体系。本文将深入剖析各种请求方法的实现原理、适用场景和性能差异,并分享我在实际项目中的优化经验。
作为前端开发者,每天都要处理数十种请求场景:简单的数据获取、文件上传、长轮询、WebSocket连接等。不同的场景需要匹配不同的请求策略,错误的选择可能导致性能下降或用户体验受损。比如在需要兼容IE老版本的项目中,你可能不得不放弃优雅的Fetch API;而在高频交互的SPA应用中,axios的拦截器机制可能成为救命稻草。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 原生请求方法深度对比
2.1 XMLHttpRequest:古老但强大的基石
虽然现代开发中已经很少直接使用XHR,但了解它的工作机制仍然必要。这是所有JS请求的底层基础,即便是Fetch API也只是它的语法糖。
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)需要完整处理- 必须手动处理响应数据的解析(JSON.parse)
- 同步请求会阻塞UI线程(第三个参数设为false时)
实战经验:在需要上传进度反馈时,XHR仍然是最可靠的选择。通过监听
xhr.upload.onprogress可以精确获取上传进度,这是其他方法难以替代的。
2.2 Fetch API:现代Web的标准选择
Fetch API基于Promise设计,代码更简洁,但有些细节需要注意:
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));
常见陷阱:
- 默认不会携带cookie(需要设置credentials)
- 404/500等状态码不会触发catch
- 需要两次then才能获取最终数据
性能优化技巧:
- 使用AbortController实现请求取消
- 合理配置cache策略减少重复请求
- 对于大文件下载使用stream处理
3. 第三方库的实战应用
3.1 axios:企业级项目的首选
axios在拦截器、自动转换JSON等方面提供了开箱即用的体验:
javascript复制axios.get('/user', {
params: { ID: 12345 },
timeout: 5000,
headers: {'X-Custom-Header': 'foobar'}
})
.then(response => console.log(response.data))
.catch(error => console.log(error));
高级配置示例:
javascript复制// 全局配置
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// 请求拦截器
axios.interceptors.request.use(config => {
// 添加时间戳防缓存
config.params = {...config.params, _t: Date.now()};
return config;
});
// 响应拦截器
axios.interceptors.response.use(
response => response,
error => {
if (error.response.status === 401) {
// 处理token过期
router.push('/login');
}
return Promise.reject(error);
}
);
3.2 特殊场景解决方案
文件上传优化方案:
javascript复制const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('user', JSON.stringify({name: 'John'}));
axios.post('/upload', formData, {
headers: {'Content-Type': 'multipart/form-data'},
onUploadProgress: progressEvent => {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(`${percent}% uploaded`);
}
});
并发请求处理:
javascript复制const [userResponse, productResponse] = await Promise.all([
axios.get('/user/123'),
axios.get('/products')
]);
4. 高级应用与性能优化
4.1 WebSocket实时通信
当需要服务器主动推送数据时,WebSocket比轮询更高效:
javascript复制const socket = new WebSocket('wss://echo.websocket.org');
socket.onopen = () => {
socket.send('Hello Server!');
};
socket.onmessage = event => {
console.log('Message from server:', event.data);
};
// 心跳检测防止断开
setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send('ping');
}
}, 30000);
4.2 请求缓存策略
内存缓存实现:
javascript复制const cache = new Map();
async function cachedFetch(url) {
if (cache.has(url)) {
return cache.get(url);
}
const response = await fetch(url);
const data = await response.json();
cache.set(url, data);
return data;
}
更健壮的缓存方案应考虑:
- 缓存过期时间
- 根据请求参数生成唯一缓存key
- 内存清理机制防止内存泄漏
5. 安全防护与异常处理
5.1 CSRF防护实战
javascript复制// 从cookie中获取CSRF token
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
// 为每个请求添加CSRF token
axios.interceptors.request.use(config => {
config.headers['X-CSRF-Token'] = getCookie('csrf_token');
return config;
});
5.2 全链路错误处理
构建完整的错误处理体系:
javascript复制class ApiError extends Error {
constructor(message, status, data) {
super(message);
this.status = status;
this.data = data;
}
}
async function safeFetch(url, options) {
try {
const response = await fetch(url, options);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new ApiError(
errorData.message || 'Request failed',
response.status,
errorData
);
}
return await response.json();
} catch (error) {
if (error instanceof ApiError) {
// 业务逻辑错误处理
if (error.status === 401) {
redirectToLogin();
}
} else {
// 网络错误处理
showNetworkErrorToast();
}
throw error;
}
}
6. 现代浏览器API的创新应用
6.1 Beacon API:页面关闭时的可靠发送
javascript复制// 用于统计页面停留时间等场景
window.addEventListener('unload', () => {
const analyticsData = new Blob(
[JSON.stringify({ duration: getPageDuration() })],
{ type: 'application/json' }
);
navigator.sendBeacon('/analytics', analyticsData);
});
6.2 Server-Sent Events (SSE) 实时数据流
javascript复制const eventSource = new EventSource('/updates');
eventSource.onmessage = event => {
const data = JSON.parse(event.data);
updateUI(data);
};
eventSource.onerror = () => {
// 处理连接错误
eventSource.close();
setTimeout(connectSSE, 5000); // 5秒后重连
};
7. 性能监控与优化指标
关键性能指标采集:
javascript复制const startTime = performance.now();
fetch('/api/data')
.then(response => {
const ttfb = performance.now() - startTime; // 首字节时间
reportMetric('ttfb', ttfb);
return response.json();
})
.then(data => {
const totalTime = performance.now() - startTime;
reportMetric('total_time', totalTime);
});
优化建议:
- 减少请求次数(合并API)
- 压缩请求数据(使用gzip)
- 使用HTTP/2多路复用
- 预加载关键请求
- 服务端渲染首屏数据
8. 移动端特殊适配方案
网络状态检测:
javascript复制const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if (connection) {
console.log('网络类型:', connection.type);
console.log('有效网络类型:', connection.effectiveType);
console.log('流量节省模式:', connection.saveData);
connection.addEventListener('change', () => {
// 网络变化时调整请求策略
adjustRequestStrategy(connection.effectiveType);
});
}
弱网优化策略:
- 降低图片质量参数
- 使用更紧凑的数据格式(如MessagePack)
- 实现请求优先级队列
- 本地缓存兜底数据
9. Node.js环境下的特殊处理
服务器端请求注意事项:
javascript复制const axios = require('axios');
const https = require('https');
// 配置keepAlive提升性能
const agent = new https.Agent({ keepAlive: true });
axios.get('https://api.example.com', {
httpsAgent: agent,
// 必须设置User-Agent
headers: { 'User-Agent': 'MyApp/1.0' }
});
常见问题处理:
- 正确处理SSL证书问题
- 处理重定向(maxRedirects配置)
- 代理服务器配置
- DNS缓存策略优化
10. 测试与Mock方案
使用MSW实现API Mock:
javascript复制import { setupWorker, rest } from 'msw';
const worker = setupWorker(
rest.get('/user', (req, res, ctx) => {
return res(
ctx.delay(150), // 模拟网络延迟
ctx.json({ name: 'John Doe' })
);
})
);
// 启动mock服务
worker.start();
自动化测试方案:
- 使用nock拦截请求
- 测试超时/重试逻辑
- 模拟网络错误(404/500等)
- 验证请求参数和headers
11. 未来趋势与新技术展望
虽然Fetch API已经成为现代Web标准,但新的技术方案仍在不断演进。例如:
- HTTP/3带来的性能提升
- WebTransport的实验性实现
- GraphQL对传统REST的补充
- WebAssembly可能带来的二进制协议支持
在实际项目中,我通常会根据技术团队的能力评估和项目需求,选择最适合的请求策略。对于新启动的项目,Fetch API + axios的组合通常是最平衡的选择;而对于需要深度优化的特定场景,可能需要定制基于XHR的解决方案。
