Laravel 8生产环境使用Server Sent Event报ob_flush无缓冲区可刷新错误
错误原因
- 本地开发环境PHP默认开启
output_buffering配置,存在活跃输出缓冲区,调用ob_flush()可正常执行 - 生产环境通常会关闭默认输出缓冲,或Symfony StreamedResponse内部已提前处理缓冲逻辑,此时直接调用
ob_flush()无缓冲区可刷新,就会抛出该错误 - 原有代码还存在两处隐含问题:响应头
Cach-Control拼写错误(少了字母t)、SSE消息未遵循data:前缀规范,会导致前端无法正常接收事件
修复代码
直接替换原有逻辑即可:
public function notificationsCount(Request $request) { try { $response = new \Symfony\Component\HttpFoundation\StreamedResponse(function () use ($request) { // 手动开启输出缓冲区,兼容不同环境配置 ob_start(); while (true) { $notif_count = Auth::user()->unreadNotifications->count(); // 遵循SSE格式要求,添加data前缀 echo "data: " . json_encode(['data' => $notif_count]) . "\n\n"; // 先判断是否存在活跃缓冲区再刷新 if (ob_get_level() > 0) { ob_flush(); } flush(); sleep(1); if (connection_aborted()) { break; } } if (ob_get_level() > 0) { ob_end_flush(); } }); $response->headers->set('Content-Type', 'text/event-stream'); $response->headers->set('X-Accel-Buffering', 'no'); // 修复响应头拼写错误 $response->headers->set('Cache-Control', 'no-cache'); // Laravel中无需手动调用send(),直接返回响应对象即可 return $response; } catch (\Exception $e) { return response()->json(['error' => $e->getMessage()]); } }
额外生产环境检查项
- 确认Nginx/Apache等Web服务器未开启
text/event-stream类型响应的gzip压缩,压缩会导致缓冲无法实时刷新 - 若使用CDN,需配置SSE接口的缓存规则为不缓存,避免CDN缓冲响应内容
内容的提问来源于stack exchange,提问作者Ausaf Liaquat
相关产品推荐
相关产品推荐

