本文目录导读:

在Laravel中,实现实时进度更新推荐使用WebSocket,但并非必须,以下是详细的方案对比和实现建议:
为什么推荐WebSocket?
实时性要求
- WebSocket:全双工通信,服务器可主动推送进度数据
- HTTP轮询:需要客户端反复请求,延迟高且浪费资源
典型场景
- 文件上传/处理进度
- 长时间运行的任务(导出、批量操作)
- 实时数据同步
Laravel中的WebSocket方案
Laravel Reverb(推荐,Laravel 10+)
// 1. 安装
composer require laravel/reverb
// 2. 配置广播
// config/broadcasting.php
'connections' => [
'reverb' => [
'driver' => 'reverb',
'key' => env('REVERB_APP_KEY'),
'secret' => env('REVERB_APP_SECRET'),
'app_id' => env('REVERB_APP_ID'),
'options' => [
'host' => env('REVERB_HOST'),
'port' => env('REVERB_PORT'),
],
],
],
// 3. 创建事件
php artisan make:event TaskProgress
// 4. 事件类
class TaskProgress implements ShouldBroadcast
{
public $progress;
public $taskId;
public function __construct($taskId, $progress)
{
$this->taskId = $taskId;
$this->progress = $progress;
}
public function broadcastOn()
{
return new Channel('task.'.$this->taskId);
}
}
// 5. 触发更新
event(new TaskProgress($taskId, 50));
Laravel WebSockets(第三方包)
composer require beyondcode/laravel-websockets
Pusher(第三方服务)
// .env PUSHER_APP_ID=your-app-id PUSHER_APP_KEY=your-key PUSHER_APP_SECRET=your-secret PUSHER_APP_CLUSTER=mt1 // 使用 event(new TaskProgress($taskId, 75));
不使用WebSocket的备选方案
Server-Sent Events (SSE)
// 路由
Route::get('/progress/{taskId}', function ($taskId) {
return response()->stream(function () use ($taskId) {
while (true) {
$progress = Cache::get("task_$taskId", 0);
echo "data: $progress\n\n";
ob_flush();
flush();
if ($progress >= 100) break;
usleep(500000); // 0.5秒
}
}, 200, [
'Content-Type' => 'text/event-stream',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
]);
});
HTTP轮询(简单但不推荐)
// 前端每2秒查询一次
setInterval(async () => {
const response = await fetch(`/api/task/${taskId}/progress`);
const data = await response.json();
updateProgress(data.progress);
}, 2000);
实际应用示例:文件上传进度
HTML + JavaScript
<!-- 使用Socket.IO客户端 -->
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<script>
const socket = io('http://localhost:8080');
// 监听进度更新
socket.on('upload.progress', (data) => {
const progressBar = document.getElementById('progress');
progressBar.style.width = data.percent + '%';
progressBar.textContent = data.percent + '%';
});
// 上传文件
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
}
</script>
Laravel后端
// 控制器
class UploadController extends Controller
{
public function upload(Request $request)
{
$file = $request->file('file');
$taskId = uniqid();
// 模拟长时间处理
for ($i = 0; $i <= 100; $i += 10) {
sleep(1); // 模拟处理时间
// 广播进度
broadcast(new TaskProgress($taskId, $i));
}
return response()->json(['taskId' => $taskId]);
}
}
决策建议
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 新项目(Laravel 10+) | Reverb | 官方支持,性能好,易于集成 |
| 已有Pusher账号 | Pusher | 节省服务器资源,无需维护 |
| 简单进度展示 | SSE | 实现简单,无需额外服务 |
| 实时性要求不高 | 轮询 | 最简方案,但效率低 |
最佳实践
- 小规模应用:使用Reverb + Laravel Echo
- 高并发场景:考虑Redis + WebSocket集群
- 移动端优化:WebSocket比轮询省电90%
- 安全性:使用Laravel认证中间件保护WebSocket连接
对于实时进度更新,WebSocket是最优选择,Laravel Reverb提供了开箱即用的解决方案,推荐在新项目中使用。