广播消息

简介配置 redis + socket 配置广播消息。

后端

  • 安装 predis/predis composer require predis/predis
  • 去掉 config/app 中的注释;
    App\Providers\BroadcastServiceProvider::class
  • 设置 .env
    BROADCAST_DRIVER=redis
  • 创建发送公共消息事件 app/Events/MessageSend.php
    class MessageSend implements ShouldBroadcast
    {
    use Dispatchable, InteractsWithSockets, SerializesModels;
    public $message;
    public function __construct($message)
    {
        $this->message = $message;
    }
    public function broadcastAs()
    {
        return 'message.send';
    }
    public function broadcastOn()
    {
        return new Channel('message.send');
    }
    }
  • 创建发送私人消息事件;
    class PrivateMessageSend implements ShouldBroadcast
    {
    use Dispatchable, InteractsWithSockets, SerializesModels;
    public $toUserId;
    public $message;
    public function __construct($toUserId, $message)
    {
        $this->toUserId = $toUserId;
        $this->message = $message;
    }
    public function broadcastAs()
    {
        return 'private.message.send';
    }
    public function broadcastOn()
    {
        return new PrivateChannel('private.message.send.' . $this->toUserId);
    }
    }
    // routes/channels.php
    Broadcast::channel('private.message.send.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
    });
  • 创建 command 来测试;

    class SendMessage extends Command
    {
    protected $signature = 'message:send {user=0}';
    protected $description = 'Command description';
    public function __construct()
    {
        parent::__construct();
    }
    public function handle()
    {
        $userId = intval($this->argument('user'));
        $message = "hello";
        if($userId > 0) {
            event(new PrivateMessageSend($userId, $message)); // 触发事件
        } else {
            event(new MessageSend($message)); // 触发事件
        }
    
        $this->info('发送消息 : ' . json_encode($message) );
    }
    }

前端

  • 安装 redis 详见
  • 安装 laravel-echo-server npm install -g laravel-echo-server
    • 在主目录中执行 laravel-echo-server init 创建配置文件
      {
      "authHost": "http://localhost",
      "authEndpoint": "/broadcasting/auth",
      "clients": [],
      "database": "redis",
      "databaseConfig": {
      "redis": {},
      "sqlite": {
          "databasePath": "/database/laravel-echo-server.sqlite"
      }
      },
      "devMode": false,
      "host": null,
      "port": "6001",
      "protocol": "http",
      "socketio": {},
      "sslCertPath": "",
      "sslKeyPath": "",
      "sslCertChainPath": "",
      "sslPassphrase": "",
      "apiOriginAllow": {
      "allowCors": false,
      "allowOrigin": "",
      "allowMethods": "",
      "allowHeaders": ""
      }
      }
  • 安装 Laravel Echo npm install --save laravel-echo
  • 安装 socket.io-client npm install --save socket.io-client
  • 创建 socket 服务
    //src/app/core/socket/socket.service.ts
    import { Inject, Injectable } from '@angular/core';
    import { environment } from '@env/environment';
    import Echo from 'laravel-echo'
    import { DA_SERVICE_TOKEN, TokenService } from '@delon/auth';
    import { LayoutModule } from '../../layout/layout.module';
    import { NzMessageService } from 'ng-zorro-antd';
    import { SettingsService } from '@delon/theme';
    (<any>window).io = require('socket.io-client');
    @Injectable()
    export class SocketService {
    echo: any;
    constructor(
    private settingService :SettingsService,
    @Inject(DA_SERVICE_TOKEN) private tokenService: TokenService) { }
    public init(): void {
    if (!environment.production) {
      console.log(
        `%c SOCKET: 初始化 `,
        `background:blue;color:#fff`,
      );
    }
    // 记得获取新的token后也要更新
    let token = this.tokenService.get().token;
    this.echo = new Echo({
      broadcaster: 'socket.io',
      host: window.location.hostname + ':6001',
      auth: {headers: {Authorization: 'Bearer ' + token}}
    });
    }
    public destroy() :void {
    if(!this.echo) return;
    let userId = this.settingService.user.id;
    this.echo.leave(`message.send`);
    this.echo.leave(`private.message.send.${userId}`);
    this.echo.disconnect();
    }
    }
  • 在 app.module.ts 的 providers 中添加 SocketService
  • 在 startup 初始化最后添加 socket 服务的初始化操作
    this.socketService.init();
  • 在 src/index.html 中添加
    <script type="text/javascript" src="http://localhost:6001/socket.io/socket.io.js"></script>
  • 在 src/polyfills.ts 中添加
    (window as any).global = window;

本文章首发在 Laravel China 社区