Объяснение Laravel Echo

задняя часть внешний интерфейс сервер Laravel

Посмотрите исходный код, проанализируйте полныйpublic channelпроцесс выпуска.

Это изображение из Интернета, если есть какие-либо нарушения, пожалуйста, сообщите мне, чтобы удалить его

Из приведенного выше рисунка нам нужно знать как минимум две вещи:

  1. Laravel не имеет прямого отношения к нашему фронтенду (vue), они проходят черезSocket.io ServerЧтобы сделать перевод, как это делается?
  2. как отправитьBrocadcasted Data?

Давайте проанализируем их один за другим.

BroadcastServiceProvider

BroadcastServiceProviderв основном включаетBroadcastСоответствующие пять дисков,Broadcastсобытие,BroadcastТакие методы, как очереди, относительно просты и не будут разбираться, сегодня я в основном расскажу о том, как пройтиredisводитьBroadcastиз.

Во-первых, простая конфигурацияBroadcastизconfig:

// broadcasting.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default Broadcaster
    |--------------------------------------------------------------------------
    |
    | This option controls the default broadcaster that will be used by the
    | framework when an event needs to be broadcast. You may set this to
    | any of the connections defined in the "connections" array below.
    |
    | Supported: "pusher", "redis", "log", "null"
    |
    */

    'default' => env('BROADCAST_DRIVER', 'null'),

    /*
    |--------------------------------------------------------------------------
    | Broadcast Connections
    |--------------------------------------------------------------------------
    |
    | Here you may define all of the broadcast connections that will be used
    | to broadcast events to other systems or over websockets. Samples of
    | each available type of connection are provided inside this array.
    |
    */

    'connections' => [

        'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                //
            ],
        ],

        'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
        ],

        'log' => [
            'driver' => 'log',
        ],

        'null' => [
            'driver' => 'null',
        ],

    ],

];

// .env
BROADCAST_DRIVER=redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

я изучил ларавельServiceProviderПринцип работыBroadcastServiceProviderспособ регистрации:

public function register()
{
    $this->app->singleton(BroadcastManager::class, function ($app) {
        return new BroadcastManager($app);
    });

    $this->app->singleton(BroadcasterContract::class, function ($app) {
        return $app->make(BroadcastManager::class)->connection();
    });

    $this->app->alias(
        BroadcastManager::class, BroadcastingFactory::class
    );
}

мы пишем отправитьBroadcastдемо:

// routes/console.php
Artisan::command('public_echo', function () {
    event(new RssPublicEvent());
})->describe('echo demo');

// app/Events/RssPublicEvent.php
<?php

namespace AppEvents;

use CarbonCarbon;
use IlluminateBroadcastingChannel;
use IlluminateQueueSerializesModels;
use IlluminateBroadcastingPrivateChannel;
use IlluminateBroadcastingPresenceChannel;
use IlluminateFoundationEventsDispatchable;
use IlluminateBroadcastingInteractsWithSockets;
use IlluminateContractsBroadcastingShouldBroadcast;

class RssPublicEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return IlluminateBroadcastingChannel|array
     */
    public function broadcastOn()
    {
        return new Channel('public_channel');
    }

    /**
     * 指定广播数据。
     *
     * @return array
     */
    public function broadcastWith()
    {
        // 返回当前时间
        return ['name' => 'public_channel_'.Carbon::now()->toDateTimeString()];
    }
}

С этим выпускомEvent, давайте посмотрим, как это работает, в основномBroadcastEventизhandleметод:

public function handle(Broadcaster $broadcaster)
{
    // 主要看,有没有自定义该 Event 名称,没有的话,直接使用类名
    $name = method_exists($this->event, 'broadcastAs')
            ? $this->event->broadcastAs() : get_class($this->event);

    $broadcaster->broadcast(
        Arr::wrap($this->event->broadcastOn()), $name,
        $this->getPayloadFromEvent($this->event)
    );
}

Сначала посмотрим, как получить параметры$this->getPayloadFromEvent($this->event):

protected function getPayloadFromEvent($event)
{
    if (method_exists($event, 'broadcastWith')) {
        return array_merge(
            $event->broadcastWith(), ['socket' => data_get($event, 'socket')]
        );
    }

    $payload = [];

    foreach ((new ReflectionClass($event))->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
        $payload[$property->getName()] = $this->formatProperty($property->getValue($event));
    }

    unset($payload['broadcastQueue']);

    return $payload;
}

В основном передайте в наш пользовательский массив, см. функцию$event->broadcastWith(), ['socket' => data_get($event, 'socket')] иEventвсе определено вpublicАтрибуты.

Завершающим этапом является реализация метода:

$broadcaster->broadcast(
    Arr::wrap($this->event->broadcastOn()), $name,
    $this->getPayloadFromEvent($this->event)
);

Глядя на пример выше,$this->event->broadcastOn()Соответствует:

return new Channel('public_channel');

Что ж, пора взглянуть на интерфейсBroadcaster.

<?php

namespace IlluminateContractsBroadcasting;

interface Broadcaster
{
    /**
     * Authenticate the incoming request for a given channel.
     *
     * @param  IlluminateHttpRequest  $request
     * @return mixed
     */
    public function auth($request);

    /**
     * Return the valid authentication response.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  mixed  $result
     * @return mixed
     */
    public function validAuthenticationResponse($request, $result);

    /**
     * Broadcast the given event.
     *
     * @param  array  $channels
     * @param  string  $event
     * @param  array  $payload
     * @return void
     */
    public function broadcast(array $channels, $event, array $payload = []);
}

Здесь представлены в основном три функции, давайте пока рассмотрим наиболее важные из них.broadcast(), Через IDE «PhpStorm» мы также можем видеть, что платформа, которая наследует этот интерфейс, в основном является платформойconfigПредусмотрено несколько приводов:

Мы начинаем спускаться, см.redisВодитель:

public function broadcast(array $channels, $event, array $payload = [])
{
    $connection = $this->redis->connection($this->connection);

    $payload = json_encode([
        'event' => $event,
        'data' => $payload,
        'socket' => Arr::pull($payload, 'socket'),
    ]);

    foreach ($this->formatChannels($channels) as $channel) {
        $connection->publish($channel, $payload);
    }
}

Это так же просто, как создатьredisсоединение, а затем данные (содержащиеevent,dataиsocketмассив), используяredis publishвыйти и ждатьlaravel-echo-serverСлушай, чтобы получить!

Примечание: Redis выпустил (publish), будут подписки, такие как:Psubscribe.

Ну, мы начали учитьсяlaravel-echo-server, чтобы увидеть, как он подписывается.

laravel-echo-server

Этот сервер специально не предусмотрен в проекте Laravel, и многие проекты используютtlaverdure/laravel-echo-server (GitHub.com/drag-verdure/…), в котором наш кумирLaradockИнструмент также интегрирован.

Итак, давайте возьмемLaradockНастроен говорить о.

.
|____Dockerfile
|____laravel-echo-server.json
|____package.json

В основном он содержит три файла: файл Dockerfile, который используется для создания контейнера;package.jsonв основном установитьtlaverdure/laravel-echo-serverплагин;laravel-echo-server.jsonФайл — это файл конфигурации для взаимодействия с Laravel.

Взгляните на содержимое Dockfile:

FROM node:alpine

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/

RUN apk add --update \n    python \n    python-dev \n    py-pip \n    build-base

RUN npm install

# Bundle app source
COPY laravel-echo-server.json /usr/src/app/laravel-echo-server.json

EXPOSE 3000
CMD [ "npm", "start" ]

в основномnode:alpineДля конца, разверните проекты на пути/usr/src/app/,Выполнение заказаnpm installУстановите плагин, обратитесь к файлуpackage.json:

{
  "name": "laravel-echo-server-docker",
  "description": "Docker container for running laravel-echo-server",
  "version": "0.0.1",
  "license": "MIT",
  "dependencies": {
    "laravel-echo-server": "^1.3.9"
  },
  "scripts": {
    "start": "laravel-echo-server start"
  }
}

Затем загрузите файл конфигурации по этому пути и, наконец, выполнитеnpm start, то есть выполнить командуlaravel-echo-server startи освободите порт 3000.

Мы запускаем контейнер, а затем входим в контейнер, чтобы увидеть файловую структуру:

воплощать в жизньdocker-compose up laravel-echo-serverМожно увидеть послеserverзапускать:

Точно так же мы также можем загрузить его исходный код для запуска для достижения эффекта.

tlaverdure/laravel-echo-server

Laravel Echo Node JS Server for Socket.io

Скачать исходный код:

git clone https://github.com/tlaverdure/laravel-echo-server.git

Войдите в проект для установки плагина:

npm install

После выполнения напрямую генерироватьdistпапка:

.
|____api
| |____http-api.js
| |____index.js
|____channels
| |____channel.js
| |____index.js
| |____presence-channel.js
| |____private-channel.js
|____cli
| |____cli.js
| |____index.js
|____database
| |____database-driver.js
| |____database.js
| |____index.js
| |____redis.js
| |____sqlite.js
|____echo-server.js
|____index.js
|____log.js
|____server.js
|____subscribers
| |____http-subscriber.js
| |____index.js
| |____redis-subscriber.js
| |____subscriber.js

При условииexampleМожно знать, что реализация выполненияEchoServerизrunметод, просто изменитеoptionsКонфигурация:

var echo = require('../dist/index.js');

var options = {
  "authHost": "http://lrss.learning.test",
  "authEndpoint": "/broadcasting/auth",
  "clients": [],
  "database": "redis",
  "databaseConfig": {
    "redis": {
      "port": "63794",
      "host": "0.0.0.0"
    }
  },
  "devMode": true,
  "host": null,
  "port": "6001",
  "protocol": "http",
  "socketio": {},
  "sslCertPath": "",
  "sslKeyPath": ""
};

echo.run(options);

Проверьте, установлено ли соединение со службой Laravel:

СмотретьLaravel-echo-serverраспечатать результат:

Описание подключено.

прямо сейчасdistпапка черезTypeScriptСгенерированный результат, разумеется, нам нужно интерпретировать через его исходный код:

.
|____api
| |____http-api.ts
| |____index.ts
|____channels
| |____channel.ts
| |____index.ts
| |____presence-channel.ts
| |____private-channel.ts
|____cli
| |____cli.ts
| |____index.ts
|____database
| |____database-driver.ts
| |____database.ts
| |____index.ts
| |____redis.ts
| |____sqlite.ts
|____echo-server.ts
|____index.ts
|____log.ts
|____server.ts
|____subscribers
| |____http-subscriber.ts
| |____index.ts
| |____redis-subscriber.ts
| |____subscriber.ts

В основном включают: интерфейс (api), канал (channels), база данных (database), Подписки (subscribers) и так далее, мы пройдемся по ним один за другим.

давайте сначала посмотримecho-server.tsизlistenфункция:

/**
 * Listen for incoming event from subscibers.
 *
 * @return {void}
 */
listen(): Promise<any> {
    return new Promise((resolve, reject) => {
        let http = this.httpSub.subscribe((channel, message) => {
            return this.broadcast(channel, message);
        });

        let redis = this.redisSub.subscribe((channel, message) => {
            return this.broadcast(channel, message);
        });

        Promise.all([http, redis]).then(() => resolve());
    });
}

Мы в основном смотрим наthis.redisSub.subscribe()не более чем черезredisПодписка, потом ставьchannelиmessageТрансляция, ладно, давайте посмотрим, как подписаться, см.redis-subscriberизsubscribe()функция:

/**
 * Subscribe to events to broadcast.
 *
 * @return {Promise<any>}
 */
subscribe(callback): Promise<any> {

    return new Promise((resolve, reject) => {
        this._redis.on('pmessage', (subscribed, channel, message) => {
            try {
                message = JSON.parse(message);

                if (this.options.devMode) {
                    Log.info("Channel: " + channel);
                    Log.info("Event: " + message.event);
                }

                callback(channel, message);
            } catch (e) {
                if (this.options.devMode) {
                    Log.info("No JSON message");
                }
            }
        });

        this._redis.psubscribe('*', (err, count) => {
            if (err) {
                reject('Redis could not subscribe.')
            }

            Log.success('Listening for redis events...');

            resolve();
        });
    });
}

Здесь мы можем увидеть ранее упомянутоеredisПодпишитесь на функцию:

this._redis.psubscribe('*', (err, count) => {
    if (err) {
        reject('Redis could not subscribe.')
    }

    Log.success('Listening for redis events...');

    resolve();
});

Ну а пока информация получена, ее можно транслировать:

this._redis.on('pmessage', (subscribed, channel, message) => {
    try {
        message = JSON.parse(message);

        if (this.options.devMode) {
            Log.info("Channel: " + channel);
            Log.info("Event: " + message.event);
        }

        // callback(channel, message);
        // return this.broadcast(channel, message);
        if (message.socket && this.find(message.socket)) {
            this.server.io.sockets.connected[message.socket](channel)
            .emit(message.event, channel, message.data);

            return true
        } else {
            this.server.io.to(channel)
            .emit(message.event, channel, message.data);

            return true
        }
    } catch (e) {
        if (this.options.devMode) {
            Log.info("No JSON message");
        }
    }
});

Это, как мы уже знаем, и LaravelLaravel-echo-serverиспользоватьredisПодписывайтесь и публикуйте сообщения. В то же время я также знаю, чтоsocket.ioи передняя частьemit/onинтерактивный.

Давайте посмотрим, как интерфейс получает сообщения.

laravel-echo

Для внешнего интерфейса необходимо установить два плагина:laravel-echoиsocket.io-client, в дополнение к выполнению настройки, прослушивание публичногоchannel, запись относительно проста:

window.Echo.channel('public_channel')
.listen('RssPublicEvent', (e) => {
    that.names.push(e.name)
});

Достигаемый эффект заключается в том, что до тех пор, пока общедоступный канал, отправленный сервером, принимаетсяpublic_channelсобытиеRssPublicEvent, будет отображено содержание сообщения:

Давайте начнем смотреть на этоLaravel-echoИсходный код:

Посмотрите информацию о конфигурации:

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001',
    auth:
        {
            headers:
                {
                'authorization': 'Bearer ' + store.getters.token
                }
        }
});

broadcasterДа:socket.io, все используют:

// echo.ts
constructor(options: any) {
    this.options = options;

    if (typeof Vue === 'function' && Vue.http) {
        this.registerVueRequestInterceptor();
    }

    if (typeof axios === 'function') {
        this.registerAxiosRequestInterceptor();
    }

    if (typeof jQuery === 'function') {
        this.registerjQueryAjaxSetup();
    }

    if (this.options.broadcaster == 'pusher') {
        this.connector = new PusherConnector(this.options);
    } else if (this.options.broadcaster == 'socket.io') {
        this.connector = new SocketIoConnector(this.options);
    } else if (this.options.broadcaster == 'null') {
        this.connector = new NullConnector(this.options);
    }
}

см. далееchannelфункция:

// echo.ts
channel(channel: string): Channel {
    return this.connector.channel(channel);
}

// socketio-connector.ts
channel(name: string): SocketIoChannel {
    if (!this.channels[name]) {
        this.channels[name] = new SocketIoChannel(
            this.socket,
            name,
            this.options
        );
    }

    return this.channels[name];
}

В основном созданоSocketIoChannel, посмотрим какlisten:

// socketio-connector.ts
listen(event: string, callback: Function): SocketIoChannel {
    this.on(this.eventFormatter.format(event), callback);

    return this;
}

Продолжай смотретьon()

on(event: string, callback: Function): void {
    let listener = (channel, data) => {
        if (this.name == channel) {
            callback(data);
        }
    };

    this.socket.on(event, listener);
    this.bind(event, listener);
}

На данный момент это относительно ясно, просто используйтеthis.socket.on(event, listener);

Примечание: Подробнее оsocketio/socket.io-client, можно посмотреть на официальном сайте:GitHub.com/socketIO/so…

Суммировать

До сих пор, интерпретируя эти плагины и исходные коды, мы в основном проходили черезpublic channelПроцесс.

Этот процесс в основном касается:

  1. Простые 16 шагов, чтобы пройти через использование Laravel Echo
  2. См. исходный код Laravel, чтобы понять процесс загрузки ServiceProvider.

Следующим шагом будет посмотреть, как разобратьprivate channel?

прочитай этоpublic channelпроцесс, мы должны поговорить о том, как пройти черезprivate channel.

В этой статье объединены ранее использовавшиесяJWTсделать проверку личности.

Но этот процесс, мы должны сначала начать с переднего конца.

socker.io

Давайте сначала напишу демонстрацию:

window.Echo.private('App.User.3')
.listen('RssCreatedEvent', (e) => {
    that.names.push(e.name)
});

создать первыйprivate channel:

/**
 * Get a private channel instance by name.
 *
 * @param  {string} name
 * @return {SocketIoChannel}
 */
privateChannel(name: string): SocketIoPrivateChannel {
    if (!this.channels['private-' + name]) {
        this.channels['private-' + name] = new SocketIoPrivateChannel(
            this.socket,
            'private-' + name,
            this.options
        );
    }

    return this.channels['private-' + name];
}

это сpublic channelРазница в том, чтоprivate channelизchannelувеличение имениprivate-.

Затем нам нужно добавить информацию аутентификации для каждого запроса.headers:

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001',
    auth:
        {
            headers:
                {
                    'authorization': 'Bearer ' + store.getters.token
                }
        }
});

Здесь мы используемstore.getters.tokenхранитсяjwtАутентификация выдается после входа в системуtoken.

Ну, пока страница носит инновации, она пойдет вLaravel-echo-serverОтправитьsubscribeсобытие:

/**
 * Subscribe to a Socket.io channel.
 *
 * @return {object}
 */
subscribe(): any {
    this.socket.emit('subscribe', {
        channel: this.name,
        auth: this.options.auth || {}
    });
}

ПосмотримLaravel-echo-serverКак получить это событие и поставитьauth, это,jwt tokenОтправлено на задний план? Прежде чем мы изучаем, как отправить его, мы все еще ставим Larave'sprivate channel Eventпостроен.

RssCreatedEvent

Мы создаем LaravelPrivateChannel:

// RssCreatedEvent
<?php

namespace AppEvents;

use AppUser;
use CarbonCarbon;
use IlluminateBroadcastingChannel;
use IlluminateQueueSerializesModels;
use IlluminateBroadcastingPrivateChannel;
use IlluminateBroadcastingPresenceChannel;
use IlluminateFoundationEventsDispatchable;
use IlluminateBroadcastingInteractsWithSockets;
use IlluminateContractsBroadcastingShouldBroadcast;

class RssCreatedEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return IlluminateBroadcastingChannel|array
     */
    public function broadcastOn()
    {
        // 14. 创建频道
        info('broadcastOn');
        return new PrivateChannel('App.User.3');
    }

    /**
     * 指定广播数据。
     *
     * @return array
     */
    public function broadcastWith()
    {
        // 返回当前时间
        return ['name' => 'private_channel_'.Carbon::now()->toDateTimeString()];
    }
}

// routes/console.php
Artisan::command('echo', function () {
    event(new RssCreatedEvent());
})->describe('echo demo');

в сочетании с jwt

ИсправлятьBroadcastServiceproviderМаршрут аутентификации для API:

// 修改前
// Broadcast::routes();

// 修改后
Broadcast::routes(["middleware" => "auth:api"]);

Конечно, наш метод аутентификации также был изменен на метод JWT:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],

...

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],

Наконец, не забудьте поставитьBroadcastServiceproviderПрисоединяйсяapp.configсередина.

Примечание: Подробнее оJWTДобро пожаловать в предыдущие статьи

  1. «Изучите аутентификацию пользователя Lumen (1)»
  2. Изучение аутентификации пользователя Lumen (2) — Использование плагина jwt-auth

Laravel-echo-server

С передним и задним концамиprivate channel, необходимо использоватьLaravel-echo-serverподключить.

Поговорим о том, как получить фронтендsubscribeсобытия иtoken.

Первый взглядecho-serverинициализация:

init(io: any): Promise<any> {
    return new Promise((resolve, reject) => {
        this.channel = new Channel(io, this.options);
        this.redisSub = new RedisSubscriber(this.options);
        this.httpSub = new HttpSubscriber(this.server.express, this.options);
        this.httpApi = new HttpApi(io, this.channel, this.server.express, this.options.apiOriginAllow);
        this.httpApi.init();

        this.onConnect();
        this.listen().then(() => resolve(), err => Log.error(err));
    });
}

в,this.onConnect():

onConnect(): void {
    this.server.io.on('connection', socket => {
        this.onSubscribe(socket);
        this.onUnsubscribe(socket);
        this.onDisconnecting(socket);
        this.onClientEvent(socket);
    });
}

Зарегистрировано четыре основных события, на первое нужно обратить внимание:

onSubscribe(socket: any): void {
    socket.on('subscribe', data => {
        this.channel.join(socket, data);
    });
}

Это перекликается с интерфейсом, затем посмотрите наjoinфункция:

join(socket, data): void {
    if (data.channel) {
        if (this.isPrivate(data.channel)) {
            this.joinPrivate(socket, data);
        } else {
            socket.join(data.channel);
            this.onJoin(socket, data.channel);
        }
    }
}

СмотретьisPrivate()функция:

/**
 * Channels and patters for private channels.
 *
 * @type {array}
 */
protected _privateChannels: string[] = ['private-*', 'presence-*'];
    
    
/**
 * Check if the incoming socket connection is a private channel.
 *
 * @param  {string} channel
 * @return {boolean}
 */
isPrivate(channel: string): boolean {
    let isPrivate = false;

    this._privateChannels.forEach(privateChannel => {
        let regex = new RegExp(privateChannel.replace('*', '.*'));
        if (regex.test(channel)) isPrivate = true;
    });

    return isPrivate;
}

Это также подтверждено, почемуprivate channelбытьprivate-Началось. Затем посмотрите на код:

/**
 * Join private channel, emit data to presence channels.
 *
 * @param  {object} socket
 * @param  {object} data
 * @return {void}
 */
joinPrivate(socket: any, data: any): void {
    this.private.authenticate(socket, data).then(res => {
        socket.join(data.channel);

        if (this.isPresence(data.channel)) {
            var member = res.channel_data;
            try {
                member = JSON.parse(res.channel_data);
            } catch (e) { }

            this.presence.join(socket, data.channel, member);
        }

        this.onJoin(socket, data.channel);
    }, error => {
        if (this.options.devMode) {
            Log.error(error.reason);
        }

        this.io.sockets.to(socket.id)
            .emit('subscription_error', data.channel, error.status);
    });
}

просто потому что этоprivate channel, поэтому вам нужно пройти процесс аутентификации:

/**
 * Send authentication request to application server.
 *
 * @param  {any} socket
 * @param  {any} data
 * @return {Promise<any>}
 */
authenticate(socket: any, data: any): Promise<any> {
    let options = {
        url: this.authHost(socket) + this.options.authEndpoint,
        form: { channel_name: data.channel },
        headers: (data.auth && data.auth.headers) ? data.auth.headers : {},
        rejectUnauthorized: false
    };

    return this.serverRequest(socket, options);
}

/**
 * Send a request to the server.
 *
 * @param  {any} socket
 * @param  {any} options
 * @return {Promise<any>}
 */
protected serverRequest(socket: any, options: any): Promise<any> {
    return new Promise<any>((resolve, reject) => {
        options.headers = this.prepareHeaders(socket, options);
        let body;

        this.request.post(options, (error, response, body, next) => {
            if (error) {
                if (this.options.devMode) {
                    Log.error(`[${new Date().toLocaleTimeString()}] - Error authenticating ${socket.id} for ${options.form.channel_name}`);
                    Log.error(error);
                }

                reject({ reason: 'Error sending authentication request.', status: 0 });
            } else if (response.statusCode !== 200) {
                if (this.options.devMode) {
                    Log.warning(`[${new Date().toLocaleTimeString()}] - ${socket.id} could not be authenticated to ${options.form.channel_name}`);
                    Log.error(response.body);
                }

                reject({ reason: 'Client can not be authenticated, got HTTP status ' + response.statusCode, status: response.statusCode });
            } else {
                if (this.options.devMode) {
                    Log.info(`[${new Date().toLocaleTimeString()}] - ${socket.id} authenticated for: ${options.form.channel_name}`);
                }

                try {
                    body = JSON.parse(response.body);
                } catch (e) {
                    body = response.body
                }

                resolve(body);
            }
        });
    });
}

На данный момент, я полагаю, вы можете это увидеть, и пошлете переднюю частьauth.headersПрисоединяйтесь к запросу, отправленному в фоновом режиме.

контрольная работа

Ок, тестируем, сначала обновите страницу, присоединяйтесьprivate channelсередина,

Затем в фоновом режиме отправьте событие, чтобы узнать, может ли внешний интерфейс его получить.

Суммировать

Пока что в основном объясняется, как создатьprivate channel, затем используйтеjwtаутентификация и, наконец,EventКонтент высылается.

Далее мы можем увидеть, как построитьchat room, а затем к чату присоединяются другие клиенты.

*Продолжение следует