本文目录导读:

- 传统 HTTP 请求(最基础)
- SSE (Server-Sent Events) - 推荐
- WebSocket(双向通信)
- 使用 Laravel Echo(如果使用 Laravel)
- 使用第三方推送服务
- 实时消息中间件方案
- 最佳实践建议
- 完整示例:SSE 实现实时通知
在 PHP 中推送数据到前端有几种常见方式,主要取决于应用场景,以下是详细的解决方案:
传统 HTTP 请求(最基础)
AJAX 轮询
// frontend.js
setInterval(() => {
fetch('/api/get-data')
.then(res => res.json())
.then(data => {
updateUI(data);
});
}, 3000);
// backend.php
header('Content-Type: application/json');
echo json_encode($data);
SSE (Server-Sent Events) - 推荐
SSE 是单向推送,服务器向客户端发送数据。
PHP 服务端实现
// sse.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
while (true) {
$data = getNewData(); // 获取新数据
echo "data: " . json_encode($data) . "\n\n";
ob_flush();
flush();
sleep(2); // 每2秒推送一次
}
前端接收
// frontend.js
const eventSource = new EventSource('sse.php');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
updateUI(data);
};
eventSource.onerror = (error) => {
console.error('SSE error:', error);
eventSource.close();
};
WebSocket(双向通信)
需要安装 WebSocket 库,推荐使用 Ratchet 或 Swoole。
使用 Ratchet 示例
composer require cboden/ratchet
// server.php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
class PushServer implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "New connection: {$conn->resourceId}\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
// 广播消息给所有客户端
foreach ($this->clients as $client) {
$client->send($msg);
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "Error: {$e->getMessage()}\n";
$conn->close();
}
}
$server = IoServer::factory(
new HttpServer(
new WsServer(
new PushServer()
)
),
8080
);
echo "WebSocket server started\n";
$server->run();
前端 WebSocket 客户端
// frontend.js
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = () => {
console.log('WebSocket connection established');
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
updateUI(data);
};
ws.onclose = () => {
console.log('WebSocket connection closed');
};
// 发送消息
function sendMessage(message) {
ws.send(JSON.stringify(message));
}
使用 Laravel Echo(如果使用 Laravel)
服务端配置
// config/broadcasting.php
'default' => env('BROADCAST_DRIVER', 'pusher'),
// .env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=your_app_id
PUSHER_APP_KEY=your_key
PUSHER_APP_SECRET=your_secret
PUSHER_APP_CLUSTER=mt1
发送事件
// Laravel Controller broadcast(new NewOrderCreated($order));
前端订阅
// frontend.js
import Echo from "laravel-echo";
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
// 监听事件
Echo.channel('orders')
.listen('NewOrderCreated', (e) => {
updateUI(e.order);
});
使用第三方推送服务
使用 Firebase Cloud Messaging (FCM)
// send_push.php
require 'vendor/autoload.php';
use Kreait\Firebase\Factory;
$factory = (new Factory)
->withServiceAccount('path/to/firebase_credentials.json');
$messaging = $factory->createMessaging();
$message = [
'notification' => [
'title' => '新消息',
'body' => '您有一条新通知',
],
'topic' => 'news'
];
$messaging->send($message);
实时消息中间件方案
# 使用 Redis Pub/Sub
// publish.php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->publish('news', json_encode($data));
// subscribe.php
$redis->subscribe(['news'], function($redis, $channel, $message) {
// 处理消息并推送
});
最佳实践建议
- 简单场景:使用 SSE,实现简单,自动重连
- 双向通信:使用 WebSocket
- 已用 Laravel:使用 Laravel Echo + Pusher
- 移动端:使用 FCM 或 APNs
- 高并发:考虑使用 Swoole 扩展
完整示例:SSE 实现实时通知
// notification_sse.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no'); // Nginx 禁用缓冲
$lastId = 0;
while (true) {
$data = fetchNotifications($lastId);
if ($data) {
echo "id: {$lastId}\n";
echo "event: notification\n";
echo "data: " . json_encode($data) . "\n\n";
ob_flush();
flush();
}
usleep(500000); // 0.5秒
}
选择哪种方案取决于:
- 实时性要求
- 是否需要双向通信
- 服务器资源
- 开发复杂度
- 浏览器兼容性要求