本文目录导读:

PHP 服务端事件(Server-Sent Events, SSE)是一种允许服务器主动向客户端推送数据的技术,在 PHP 中实现 SSE 相对简单,主要通过设置响应头并不断输出特定格式的数据来完成。
基本实现原理
服务器端 PHP 脚本
<?php
// 设置 SSE 需要的响应头
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
// 禁用输出缓冲
@ob_end_flush();
ob_implicit_flush(true);
// 无限循环发送事件
while (true) {
// 获取当前时间
$time = date('Y-m-d H:i:s');
// 发送事件
echo "data: 当前时间: {$time}\n\n";
flush();
// 每 5 秒发送一次
sleep(5);
// 检测客户端是否断开连接
if (connection_aborted()) {
break;
}
}
?>
客户端 JavaScript 代码
<!DOCTYPE html>
<html>
<head>SSE Demo</title>
</head>
<body>
<div id="events"></div>
<script>
// 创建 EventSource 连接
const eventSource = new EventSource('sse.php');
// 监听消息事件
eventSource.onmessage = function(event) {
const eventsDiv = document.getElementById('events');
const p = document.createElement('p');
p.textContent = `收到: ${event.data}`;
eventsDiv.appendChild(p);
};
// 监听错误
eventSource.onerror = function(event) {
console.error('SSE 连接错误:', event);
};
// 关闭连接的函数
function closeConnection() {
eventSource.close();
console.log('连接已关闭');
}
</script>
</body>
</html>
高级功能实现
带事件类型的 SSE
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
// 发送不同事件类型
echo "event: userUpdate\n";
echo "data: {\"username\": \"john\", \"action\": \"login\"}\n\n";
flush();
echo "event: notification\n";
echo "id: 123\n"; // 可选的事件ID
echo "data: 你有新的消息\n\n";
flush();
客户端监听特定事件:
const eventSource = new EventSource('events.php');
eventSource.addEventListener('userUpdate', function(e) {
console.log('用户更新:', JSON.parse(e.data));
});
eventSource.addEventListener('notification', function(e) {
console.log('通知:', e.data);
});
带重连机制的 SSE
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
// 设置重连时间(毫秒)
echo "retry: 3000\n\n";
$counter = 0;
while (true) {
$counter++;
// 发送带 ID 的事件,确保客户端能跟踪
echo "id: {$counter}\n";
echo "data: 消息 #{$counter}\n\n";
flush();
if (connection_aborted()) {
break;
}
sleep(2);
}
?>
从数据库推送事件
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
// 数据库连接
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
$lastCheck = time();
while (true) {
// 检查是否有新数据
$stmt = $pdo->prepare("SELECT * FROM notifications WHERE created_at > :last_time");
$stmt->execute([':last_time' => date('Y-m-d H:i:s', $lastCheck)]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "event: {$row['type']}\n";
echo "data: " . json_encode($row) . "\n\n";
flush();
}
$lastCheck = time();
if (connection_aborted()) {
break;
}
sleep(2); // 每 2 秒检查一次
}
?>
重要注意事项
PHP 配置要求
; 需要在 php.ini 中设置 max_execution_time = 0 ; 取消执行时间限制 output_buffering = Off ; 关闭输出缓冲
服务器配置
Apache:
# 启用 mod_headers 模块 Header set Cache-Control "no-cache"
Nginx:
# 禁用代理缓冲 proxy_buffering off; proxy_cache off; fastcgi_buffering off;
性能优化建议
<?php
// 使用数据库连接池或持久连接
// 实现心跳机制防止超时
while (true) {
// 发送心跳
echo ": heartbeat\n\n";
flush();
// 实际业务逻辑
// ...
// 控制频率
usleep(500000); // 0.5秒
}
?>
完整示例:实时消息通知系统
服务器端 (notifications.php)
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
// 身份验证(示例)
$user_id = $_GET['user_id'] ?? die('User ID required');
// 建立与 Redis 的连接
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 订阅用户的通知频道
$channel = "user:{$user_id}:notifications";
while (true) {
// 从 Redis 获取新消息
$message = $redis->blPop([$channel], 2);
if ($message) {
$data = json_decode($message[1], true);
echo "event: {$data['type']}\n";
echo "data: " . json_encode([
'title' => $data['title'],
'message' => $data['message'],
'timestamp' => time()
]) . "\n\n";
flush();
}
// 发送心跳
echo ": keepalive\n\n";
flush();
if (connection_aborted()) {
break;
}
}
?>
客户端 (index.html)
<!DOCTYPE html>
<html>
<head>实时通知</title>
</head>
<body>
<div id="notifications"></div>
<script>
const userId = 1; // 当前用户ID
const eventSource = new EventSource(`notifications.php?user_id=${userId}`);
eventSource.addEventListener('message', function(e) {
const notification = JSON.parse(e.data);
showNotification(notification);
});
eventSource.addEventListener('alert', function(e) {
const alert = JSON.parse(e.data);
showAlert(alert);
});
function showNotification(data) {
const div = document.getElementById('notifications');
const p = document.createElement('p');
p.textContent = `[${data.title}] ${data.message}`;
div.appendChild(p);
}
function showAlert(data) {
alert(`紧急通知: ${data.message}`);
}
eventSource.onerror = function() {
console.log('尝试重新连接...');
};
</script>
</body>
</html>
SSE 比 WebSocket 更适合简单的服务器推送场景,实现更简单,且原生支持 HTTP 协议,但请注意它只支持单向通信(服务器→客户端),且连接数较多时对服务器资源消耗较大。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播