Skip to content

网络请求

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 Unavailable

Fetch 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的特点?

  • 双向通信
  • 实时性高
  • 连接保持
  • 低延迟

通过理解网络请求的各种技术和最佳实践,可以更好地处理前后端数据交互。

好好学习,天天向上