Laravel 广播

使用 redis + socket.io 等进行 websocket 通信

Posted by cj on March 30, 2019

Laravel5.7 广播

环境为 homestead/ubuntu18.04/laravel5.7/php7.2 。。。

本想用 pusher ,他官网访问极慢,换 redis 。。。

大致步骤

  1. 编辑 config/app.php,取消对 BroadcastServiceProvider 的注释
  2. 编辑 .env,修改 BROADCAST_DRIVER=redis
  3. yarn global add laravel-echo-server --prefix /usr/local --no-bin-links
  4. laravel-echo-server init

    除了第一项 development modeyes 其他一路回车默认

  5. 创建 event, app/Events/EventMachineOperated.php,真实项目,摘录一些关键代码
     class EventMachineOperated implements ShouldBroadcast
     {
         public $message; // public 的成员都将广播出去
    
         public function broadcastOn()
         {
             return new Channel('machineStatus');
         }
     }
    
  6. 编辑 routes/channels.php,对这个频道暂时不做权限控制
     Broadcast::channel('machineStatus', function () {
         return true;
     });
    
  7. yarn add socket.io-client
  8. yarn add laravel-echo
  9. 编辑 /resources/assets/js/bootstrap.js,最底下取消注释稍作修改

     import Echo from "laravel-echo"
    
     window.io = require('socket.io-client');
    
     window.Echo = new Echo({
         broadcaster: 'socket.io',
         host: window.location.hostname + ':6001'
     });
    
  10. 编辑 resources/views/pages/test_websocket.blade.php
    <!DOCTYPE html>
    <html lang="">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    
        <!-- CSRF Token -->
        <meta name="csrf-token" content="">
    
        <title>Websocket Test</title>
    
        <!-- Styles -->
        <link href="" rel="stylesheet">
    </head>
    <body>
        <div id="app">
            <div class="content">
                <div class="m-b-md">
                    Websocket Test
                </div>
            </div>
        </div>
    
        <!-- receive notifications -->
            
        <script src="http://\{\{ Request::getHost() \}\}:6001/socket.io/socket.io.js"></script>
        <script src=""></script>
    
        <script>
            //Pusher.logToConsole = true;
    
            Echo.channel('machineStatus')
                .listen('EventMachineOperated', (e) => {
                    console.log('triggered');
                    console.log(e);
                });
        </script>
        <!-- receive notifications -->
    </body>
    </html>
    
  11. npm run dev
  12. php artisan horizon
  13. laravel-echo-server start
  14. 创建了个测试 api,使用 postman 调用接口后触发 EventMachineOperated 事件
  15. 创建相关路由,不提
  16. 浏览器打开页面 http://your-website/testWebsocket,按下 F12 开调试模式,使用 postman 触发事件,有 log 产生,大功告成。
  17. 创建私有频道时,需修改 laravel-echo-server.jsonauthHost 设置项为真实域名,我这边使用 http://localhost 失败鸟。

frpc 反向代理设置

由于我的环境是域名指向公网阿里云服务器,并配置了 frps 做转发。websocket 通信用到的 6001 端口需要在防火墙放开,且需要本地 homestead 内修改 frpc 做相应设置。frp 相关资料参阅 使用frp搭建微信开发环境

frpc.ini

[websocket]
type = tcp
local_ip = 127.0.0.1
local_port = 6001
remote_port = 6001

测试时可以先执行 laravel-echo-server start,然后启动 frpc: ./frpc -c frpc.ini,在浏览器内输入 http://your-site:6001 做测试,如果输出 OK 说明配置成功。

生产环境部署

2019年4月3日21:04:19新增

当在生产环境部署时,由于网站开启了全站 HTTPS, 客户端一直无法认证通过。

查看官方文档,可以让 js 代码不再显示走 6001 端口,而是配置 nginx 转发解决。

  • 在网站的 nginx conf 中新增:

      location /socket.io {
          proxy_pass http://localhost:6001; #could be localhost if Echo and NginX are on the same box
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "Upgrade";
      }
    
  • 修改 laravel-echo-server.confauthHost 设置项为真实域名如 https://your-domain.com

  • 修改 app/resources/assets/js/bootstrap.js,去掉显示指定的 6001 端口:

      window.Echo = new Echo({
          broadcaster: 'socket.io',
          host: window.location.hostname
      });        
    
  • 修改引入 socket.io.jsblade view,同样去除 6001 端口:

      <script src="https://\{\{  Request::getHost() \}\}/socket.io/socket.io.js"></script>
    

如此一来,浏览器端都是访问的 https://your-domain.com,让 nginx 帮我们处理 locationsocket.io 的情况,自动转发流量到 laravel-echo-server 的服务接口 http://localhost:6001,完美。

Reference