You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Server Sent Events (SSE) 服务端内容无法推送至客户端问题求助

问题原因与解决方案

核心问题1:控制器属性无法跨请求共享

  • PHP HTTP请求是完全隔离的生命周期,每个请求都会重新初始化控制器实例,sendContent请求中赋值的$this->data,和EventSource发起的getData请求的控制器实例毫无关联,数据无法互通。哪怕改为静态属性,普通FPM模式下请求结束后所有资源都会销毁,依然无法跨请求留存数据。

核心问题2:SSE长连接逻辑错误

  • SSE需要服务端保持连接持续流式输出,你当前的getData方法直接返回单次响应就断开连接,EventSource只会拿到一次空数据,之后进入自动重连循环,永远接收不到后续更新的推送。

核心问题3:客户端解析逻辑不匹配

  • 客户端代码用JSON.parse(event.data)解析推送内容,但服务端直接返回的是原始字符串,没有做JSON序列化,解析失败会抛出JS错误,直接中断onmessage回调执行。

修复方案

1. 服务端Laravel代码修改

首先使用跨请求存储(示例用Laravel缓存,也可替换为Redis、数据库等),改造SSE接口保持长连接循环推送:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;
use Illuminate\Http\Request;

class MiscController extends Controller {

   public function sendContent(Request $request) {
      $content = $request['content'];
      if (!is_null($content)) {
          // 存储推送内容,带上版本号方便客户端判断更新
          $cachedData = Cache::get('sse_push_data', ['version' => 0, 'content' => '']);
          $cachedData['version']++;
          $cachedData['content'] = $content;
          Cache::put('sse_push_data', $cachedData);
      }
      return response()->json(['status' => 'ok']);
   }


   public function getData() {
       // 关闭执行超时
       set_time_limit(0);
       // 关闭输出缓冲
       ob_implicit_flush(true);
       ob_end_flush();

       $response = response()->stream(function () {
           $lastVersion = 0;
           while (true) {
               $cachedData = Cache::get('sse_push_data', ['version' => 0, 'content' => '']);
               // 有更新才推送
               if ($cachedData['version'] > $lastVersion) {
                   $lastVersion = $cachedData['version'];
                   // 输出SSE格式,JSON序列化内容匹配客户端解析逻辑
                   echo "data: " . json_encode($cachedData['content']) . "\n\n";
               }
               // 每2秒检查一次更新,可自行调整间隔
               sleep(2);
           }
       }, 200, [
           'Content-Type' => 'text/event-stream',
           'Cache-Control' => 'no-cache',
           'Connection' => 'keep-alive',
           'X-Accel-Buffering' => 'no' // 禁用Nginx反向代理缓冲,很重要
       ]);

       return $response;
   }

}

2. 客户端代码优化

添加错误监听方便排查,同时补充异常处理逻辑:

$(document).ready(function($) {
    var lastMsg = '';
    const source = new EventSource("/misc/getData");
    source.onmessage = function(event) {
        console.log('收到推送:', event.data);
        var data = JSON.parse(event.data);
        if (data !== lastMsg) {
            $('#result').empty();
            $('#result').append('Result: ' + data);
            lastMsg = data;
        }
    };
    // 添加错误监听排查问题
    source.onerror = function(error) {
        console.error('SSE连接错误:', error);
    };
});

额外注意事项

  • 如果用Nginx做反向代理,必须加X-Accel-Buffering: no头,否则Nginx会缓冲输出内容,不会实时推送到客户端
  • FPM模式下长连接资源占用较高,并发量较大的场景建议改用Swoole、Workerman等常驻进程框架实现SSE推送
  • 可以给SSE推送加id字段,方便连接断开后客户端从断点续传

内容的提问来源于stack exchange,提问作者jgarcias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 21:15:03