前后端通信方式

常见的前后端数据交互方案及代码示例

问题

前后端如何通信?有哪些常见的通信方式?

解答

1. AJAX (XMLHttpRequest)

传统的异步请求方式。

// 创建 XHR 对象
const xhr = new XMLHttpRequest();

// 配置请求
xhr.open('GET', '/api/users', true);

// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/json');

// 监听状态变化
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    if (xhr.status === 200) {
      const data = JSON.parse(xhr.responseText);
      console.log(data);
    } else {
      console.error('请求失败:', xhr.status);
    }
  }
};

// 发送请求
xhr.send();

// POST 请求示例
const postXhr = new XMLHttpRequest();
postXhr.open('POST', '/api/users', true);
postXhr.setRequestHeader('Content-Type', 'application/json');
postXhr.onload = function() {
  if (postXhr.status === 200) {
    console.log('创建成功');
  }
};
postXhr.send(JSON.stringify({ name: 'Tom', age: 18 }));

2. Fetch API

现代浏览器提供的请求 API,基于 Promise。

// GET 请求
fetch('/api/users')
  .then(response => {
    if (!response.ok) {
      throw new Error('请求失败');
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error(error));

// POST 请求
fetch('/api/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Tom', age: 18 })
})
  .then(response => response.json())
  .then(data => console.log(data));

// async/await 写法
async function getUsers() {
  try {
    const response = await fetch('/api/users');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('请求出错:', error);
  }
}

3. WebSocket

全双工通信,适合实时场景。

// 创建 WebSocket 连接
const ws = new WebSocket('ws://localhost:8080');

// 连接建立
ws.onopen = function() {
  console.log('连接已建立');
  ws.send('Hello Server');
};

// 接收消息
ws.onmessage = function(event) {
  console.log('收到消息:', event.data);
};

// 连接关闭
ws.onclose = function(event) {
  console.log('连接已关闭', event.code, event.reason);
};

// 连接错误
ws.onerror = function(error) {
  console.error('连接错误:', error);
};

// 发送消息
function sendMessage(msg) {
  if (ws.readyState === WebSocket.OPEN) {
    ws.send(msg);
  }
}

// 关闭连接
function closeConnection() {
  ws.close();
}

4. Server-Sent Events (SSE)

服务器向客户端推送数据,单向通信。

// 创建 SSE 连接
const eventSource = new EventSource('/api/events');

// 接收消息
eventSource.onmessage = function(event) {
  console.log('收到消息:', event.data);
};

// 监听特定事件
eventSource.addEventListener('update', function(event) {
  console.log('更新事件:', event.data);
});

// 连接建立
eventSource.onopen = function() {
  console.log('SSE 连接已建立');
};

// 错误处理
eventSource.onerror = function(error) {
  console.error('SSE 错误:', error);
  eventSource.close();
};

5. JSONP

跨域解决方案,仅支持 GET 请求。

// JSONP 实现
function jsonp(url, callbackName) {
  return new Promise((resolve, reject) => {
    // 创建 script 标签
    const script = document.createElement('script');
    
    // 定义回调函数
    window[callbackName] = function(data) {
      resolve(data);
      // 清理
      document.body.removeChild(script);
      delete window[callbackName];
    };
    
    // 设置 src
    script.src = `${url}?callback=${callbackName}`;
    script.onerror = reject;
    
    // 插入页面
    document.body.appendChild(script);
  });
}

// 使用
jsonp('http://api.example.com/data', 'handleData')
  .then(data => console.log(data));

6. postMessage

跨窗口/跨域通信。

// 发送方(父窗口)
const iframe = document.getElementById('myIframe');
iframe.contentWindow.postMessage(
  { type: 'greeting', data: 'Hello' },
  'https://target-origin.com'
);

// 接收方(iframe 内)
window.addEventListener('message', function(event) {
  // 验证来源
  if (event.origin !== 'https://parent-origin.com') {
    return;
  }
  
  console.log('收到消息:', event.data);
  
  // 回复消息
  event.source.postMessage(
    { type: 'reply', data: 'Hi' },
    event.origin
  );
});

各方式对比

方式双向通信跨域实时性适用场景
AJAX需配置 CORS普通请求
Fetch需配置 CORS普通请求
WebSocket支持聊天、游戏、实时数据
SSE单向需配置 CORS消息推送、实时通知
JSONP支持跨域 GET 请求
postMessage支持跨窗口通信

关键点

  • AJAX/Fetch:最常用的请求方式,Fetch 基于 Promise 更现代
  • WebSocket:全双工通信,适合实时交互场景
  • SSE:服务器单向推送,比 WebSocket 轻量,自动重连
  • JSONP:利用 script 标签跨域,只支持 GET,有安全风险
  • postMessage:跨窗口通信的标准方案,需验证 origin