网络请求
HTTP协议
HTTP版本
- HTTP/1.0: 每个请求都需要新的连接
- HTTP/1.1: 支持持久连接、管道化
- HTTP/2: 多路复用、头部压缩
- HTTP/3: 基于QUIC协议
HTTP请求方法
javascript
// GET: 获取资源
fetch('https://api.example.com/data', {
method: 'GET'
});
// POST: 创建资源
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John' })
});
// PUT: 更新资源
fetch('https://api.example.com/data/1', {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'Jane' })
});
// DELETE: 删除资源
fetch('https://api.example.com/data/1', {
method: 'DELETE'
});
// PATCH: 部分更新
fetch('https://api.example.com/data/1', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ age: 30 })
});HTTP状态码
javascript
// 2xx: 成功
200 OK
201 Created
204 No Content
// 3xx: 重定向
301 Moved Permanently
302 Found
304 Not Modified
// 4xx: 客户端错误
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
// 5xx: 服务器错误
500 Internal Server Error
502 Bad Gateway
503 Service UnavailableFetch API
基本用法
javascript
// GET请求
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
// POST请求
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John' })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));请求头
javascript
fetch('https://api.example.com/data', {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123',
'Accept': 'application/json',
'User-Agent': 'MyApp/1.0'
}
});响应处理
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('https://api.example.com/data')
.then(response => {
if (response.status === 404) {
throw new Error('Resource not found');
}
if (response.status === 401) {
throw new Error('Unauthorized');
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('Error:', error));超时处理
javascript
function fetchWithTimeout(url, options = {}, timeout = 5000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Request timeout')), timeout)
)
]);
}
fetchWithTimeout('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));并发请求
javascript
// Promise.all
Promise.all([
fetch('https://api.example.com/data1'),
fetch('https://api.example.com/data2'),
fetch('https://api.example.com/data3')
])
.then(responses => Promise.all(responses.map(response => response.json())))
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
// Promise.allSettled
Promise.allSettled([
fetch('https://api.example.com/data1'),
fetch('https://api.example.com/data2'),
fetch('https://api.example.com/data3')
])
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Request ${index + 1} succeeded:`, result.value);
} else {
console.error(`Request ${index + 1} failed:`, result.reason);
}
});
});XMLHttpRequest
基本用法
javascript
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data');
xhr.send();
xhr.onload = function() {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
console.log(data);
}
};
xhr.onerror = function() {
console.error('Request failed');
};POST请求
javascript
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/data');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({ name: 'John' }));
xhr.onload = function() {
if (xhr.status === 201) {
const data = JSON.parse(xhr.responseText);
console.log(data);
}
};进度监听
javascript
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/large-file');
xhr.onprogress = function(event) {
if (event.lengthComputable) {
const percent = (event.loaded / event.total) * 100;
console.log(`Progress: ${percent}%`);
}
};
xhr.onload = function() {
console.log('Download complete');
};
xhr.send();Axios
基本用法
javascript
// GET请求
axios.get('https://api.example.com/data')
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));
// POST请求
axios.post('https://api.example.com/data', { name: 'John' })
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));请求配置
javascript
axios({
method: 'POST',
url: 'https://api.example.com/data',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
data: { name: 'John' },
timeout: 5000
})
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));拦截器
javascript
// 请求拦截器
axios.interceptors.request.use(
config => {
config.headers.Authorization = 'Bearer token123';
return config;
},
error => {
return Promise.reject(error);
}
);
// 响应拦截器
axios.interceptors.response.use(
response => {
return response.data;
},
error => {
if (error.response.status === 401) {
console.error('Unauthorized');
}
return Promise.reject(error);
}
);并发请求
javascript
axios.all([
axios.get('https://api.example.com/data1'),
axios.get('https://api.example.com/data2'),
axios.get('https://api.example.com/data3')
])
.then(axios.spread((data1, data2, data3) => {
console.log(data1, data2, data3);
}))
.catch(error => console.error('Error:', error));WebSocket
基本用法
javascript
const socket = new WebSocket('ws://localhost:8080');
// 连接打开
socket.onopen = function() {
console.log('WebSocket连接已打开');
socket.send('Hello Server');
};
// 接收消息
socket.onmessage = function(event) {
console.log('收到消息:', event.data);
};
// 连接关闭
socket.onclose = function() {
console.log('WebSocket连接已关闭');
};
// 连接错误
socket.onerror = function(error) {
console.error('WebSocket错误:', error);
};
// 关闭连接
socket.close();心跳检测
javascript
const socket = new WebSocket('ws://localhost:8080');
let heartbeatInterval;
function startHeartbeat() {
heartbeatInterval = setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send('ping');
}
}, 30000);
}
function stopHeartbeat() {
clearInterval(heartbeatInterval);
}
socket.onopen = function() {
console.log('WebSocket连接已打开');
startHeartbeat();
};
socket.onclose = function() {
console.log('WebSocket连接已关闭');
stopHeartbeat();
};
socket.onmessage = function(event) {
if (event.data === 'pong') {
console.log('收到心跳响应');
} else {
console.log('收到消息:', event.data);
}
};断线重连
javascript
class ReconnectingWebSocket {
constructor(url) {
this.url = url;
this.socket = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectInterval = 3000;
}
connect() {
this.socket = new WebSocket(this.url);
this.socket.onopen = () => {
console.log('WebSocket连接已打开');
this.reconnectAttempts = 0;
};
this.socket.onmessage = (event) => {
console.log('收到消息:', event.data);
};
this.socket.onclose = () => {
console.log('WebSocket连接已关闭');
this.reconnect();
};
this.socket.onerror = (error) => {
console.error('WebSocket错误:', error);
};
}
reconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
setTimeout(() => this.connect(), this.reconnectInterval);
} else {
console.error('重连失败');
}
}
send(data) {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(data);
} else {
console.error('WebSocket未连接');
}
}
close() {
if (this.socket) {
this.socket.close();
}
}
}
const socket = new ReconnectingWebSocket('ws://localhost:8080');
socket.connect();CORS
简单请求
javascript
// 简单请求: GET、POST、HEAD
// Content-Type: text/plain、multipart/form-data、application/x-www-form-urlencoded
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));预检请求
javascript
// 预检请求: PUT、DELETE、PATCH
// Content-Type: application/json
fetch('https://api.example.com/data', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John' })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));携带凭证
javascript
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors',
credentials: 'include'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));面试常见问题
1. HTTP和HTTPS的区别?
- HTTP: 明文传输,不安全
- HTTPS: 加密传输,安全
2. GET和POST的区别?
- GET: 获取资源,参数在URL中,有长度限制,可缓存
- POST: 创建资源,参数在请求体中,无长度限制,不可缓存
3. 什么是CORS?
CORS(跨域资源共享)是一种机制,允许服务器声明哪些源可以访问资源。
4. Fetch和XMLHttpRequest的区别?
- Fetch: 基于Promise,更简洁,不支持进度监听
- XMLHttpRequest: 基于回调,更复杂,支持进度监听
5. WebSocket的特点?
- 双向通信
- 实时性高
- 连接保持
- 低延迟
通过理解网络请求的各种技术和最佳实践,可以更好地处理前后端数据交互。