Посмотрите исходный код, проанализируйте полныйpublic channel
процесс выпуска.
Это изображение из Интернета, если есть какие-либо нарушения, пожалуйста, сообщите мне, чтобы удалить его
Из приведенного выше рисунка нам нужно знать как минимум две вещи:
- Laravel не имеет прямого отношения к нашему фронтенду (vue), они проходят через
Socket.io Server
Чтобы сделать перевод, как это делается? - как отправить
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
Процесс.
Этот процесс в основном касается:
Следующим шагом будет посмотреть, как разобрать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
Добро пожаловать в предыдущие статьи
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
, а затем к чату присоединяются другие клиенты.
*Продолжение следует