如何将Yii2服务端与React项目对接?Fetch连接问题求最优方案
React与Yii2通信方案选型(解决Fetch不稳定问题)
一、优化原生Fetch配置(低成本改造)
如果不想替换客户端,先通过完善Fetch的核心配置解决不稳定问题:
- 添加超时与重试机制:原生Fetch无内置超时,封装带重试逻辑的函数,抵消网络波动影响
async function fetchWithRetry(url, options = {}, retries = 3, delay = 1000) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); // 5秒超时限制 const response = await fetch(url, { ...options, signal: controller.signal, headers: { 'Content-Type': 'application/json', ...options.headers } }); clearTimeout(timeoutId); if (!response.ok) throw new Error(`HTTP错误: ${response.status}`); return await response.json(); } catch (error) { if (retries > 0 && error.name !== 'AbortError') { await new Promise(resolve => setTimeout(resolve, delay)); return fetchWithRetry(url, options, retries - 1, delay * 2); } throw error; } } - Yii2端配合优化:
- 配置正确的CORS规则,在控制器
behaviors()中添加:public function behaviors() { $behaviors = parent::behaviors(); $behaviors['corsFilter'] = [ 'class' => \yii\filters\Cors::class, 'cors' => [ 'Origin' => ['http://你的React域名'], 'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'DELETE'], 'Access-Control-Request-Headers' => ['Content-Type', 'Authorization'], 'Access-Control-Allow-Credentials' => true, ], ]; return $behaviors; } - 确保接口返回标准JSON格式,统一处理后端异常,避免返回非JSON内容导致前端解析失败
- 配置正确的CORS规则,在控制器
二、使用Axios替代Fetch(更稳定的HTTP客户端)
Axios内置超时、重试、拦截器等生产级特性,比原生Fetch更适配复杂业务场景:
- React端集成Axios:
- 安装依赖:
npm install axios - 创建全局Axios实例:
import axios from 'axios'; const apiClient = axios.create({ baseURL: 'http://你的Yii2接口域名', timeout: 5000, headers: { 'Content-Type': 'application/json' } }); // 请求拦截器:统一添加认证token apiClient.interceptors.request.use(config => { const token = localStorage.getItem('auth-token'); if (token) config.headers.Authorization = `Bearer ${token}`; return config; }); // 响应拦截器:统一处理错误 apiClient.interceptors.response.use( response => response.data, error => { if (error.code === 'ECONNABORTED') { throw new Error('请求超时,请稍后重试'); } throw error.response?.data || '请求失败'; } ); export default apiClient;- 调用示例:
import apiClient from './apiClient'; async function sendMessage(data) { try { const response = await apiClient.post('/message/send', data); return response; } catch (error) { console.error(error); } } - 安装依赖:
- Yii2端适配:无需额外改造,确保接口遵循RESTful规范、返回标准JSON即可
三、WebSocket长连接(适合实时/频繁交互场景)
如果业务需要实时通信(如聊天、实时通知),WebSocket比HTTP请求更稳定,避免频繁建立连接的开销:
- Yii2端搭建WebSocket服务:
使用Ratchet库实现,步骤如下:- 安装依赖:
composer require cboden/ratchet - 创建服务器脚本(
websocket-server.php):
use Ratchet\MessageComponentInterface; use Ratchet\ConnectionInterface; use Ratchet\Server\IoServer; use Ratchet\Http\HttpServer; use Ratchet\WebSocket\WsServer; class MessageServer implements MessageComponentInterface { protected $clients; public function __construct() { $this->clients = new \SplObjectStorage; } public function onOpen(ConnectionInterface $conn) { $this->clients->attach($conn); } public function onMessage(ConnectionInterface $from, $msg) { // 解析React发送的消息,调用Yii2业务逻辑 $requestData = json_decode($msg, true); $response = ['code' => 200, 'data' => '处理完成']; $from->send(json_encode($response)); } public function onClose(ConnectionInterface $conn) { $this->clients->detach($conn); } public function onError(ConnectionInterface $conn, \Exception $e) { $conn->close(); } } $server = IoServer::factory( new HttpServer(new WsServer(new MessageServer())), 8080 ); $server->run();- 启动服务:
php websocket-server.php
- 安装依赖:
- React端连接WebSocket:
function initWebSocket() { const socket = new WebSocket('ws://你的Yii2域名:8080'); socket.onopen = () => { socket.send(JSON.stringify({ message: 'Hello Yii2' })); }; socket.onmessage = (event) => { const response = JSON.parse(event.data); console.log('收到响应:', response); }; socket.onclose = () => { // 自动重连逻辑 setTimeout(() => initWebSocket(), 3000); }; } initWebSocket();
四、统一接口规范与错误处理
无论选择哪种方案,Yii2端的接口规范是稳定性的基础:
- 统一响应格式:
// Yii2控制器返回示例 return $this->asJson([ 'code' => 200, 'message' => 'success', 'data' => $result ]); - 全局异常处理,在
config/web.php中配置:'components' => [ 'errorHandler' => [ 'errorAction' => 'site/error', 'exceptionFilter' => [ 'class' => \yii\web\ExceptionFilter::class, 'exceptionMap' => [ \yii\web\NotFoundHttpException::class => \yii\web\NotFoundHttpException::class, ], ], ], ],
内容的提问来源于stack exchange,提问作者Ильяс Каримов
相关产品推荐
相关产品推荐

