Socket.io работает только при повторном подключении

Я создаю приложение React, которое подключается к API Nodejs, и пытаюсь реализовать библиотеку Socket.io. Я следил за некоторыми учебными пособиями в Интернете, и мой код сейчас выглядит так:

API:

import express from 'express';
import socketIo from 'socket.io';
import http from 'http';

const app = express();
const port = 3300;

const server = http.createServer(app);
const io = socketIo({ 
    serveClient: false,
    transports: [ 'websocket', 'polling' ],
    pingTimeout: 3000,
    pingInterval: 3000,
    allowUpgrades: false,
    upgrade: false,
    cookie: false
}).listen(server);

io.on('connection', function(socket){
    console.info("------------------------- CONNECTED!!!");
    app.get('/change_name', (req, res) => {
        console.info("Change Name");
        const { name } = req.query;
        res.sendStatus(200);

        console.info('Emitting Event');
        socket.emit('name', name);
    });
});

server.listen(port, err => err ? throw err : console.info("Server online. Listening to port " + port);

И в моем приложении React:

import React from "react";
import openSocket from 'socket.io-client';

export default class Header extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      name: "Thiago"
    };

    console.info("Open Socket");
    const socket = openSocket('http://localhost:3300', {
      transports: [ 'websocket', 'polling' ],
    }); 
    console.info("Set event listener");
    socket.on('name', name => {
      console.info('receiving event')
      this.setState({ name });
    });
  }

  render() { /* ... */ }
}

Дело в том, что я могу заставить эту работу работать, только если веб-приложение повторно подключится к веб-сокету. Проиллюстрировать:

Запустив приложение и API, я нажимаю localhost: 8888 в своем браузере, чтобы получить доступ к приложению. API успешно регистрирует ------ CONNECTED, и я не вижу никаких ошибок на вкладке сети в моем браузере, поэтому я предполагаю, что соединение работает нормально. Но потом, когда я попадаю в маршрут /change_name, ничего не происходит. API регистрирует как Change Name, так и Emmitting Event, но браузер, кажется, никогда не получает его (receiving event не регистрируется).

Теперь, если я перейду на свой терминал и перезапущу свой API (без обновления браузера), сначала я получаю сообщение об ошибке в браузере о том, что мое ws-соединение было потеряно. Как только API снова запускается, я вижу журнал -------- CONNECTED, что означает, что браузер успешно переподключился к серверу, и если я снова нажму change_name, теперь все работает нормально! Если я обновлю браузер, все снова перестанет работать, и мне нужно снова перезапустить свой API.

Я тестировал это как на локальном, так и на удаленном сервере (AWS), и поведение было одинаковым. При первом подключении ничего не происходит, после перезапуска API и автоматического переподключения браузера все работает нормально.

Кто-нибудь знает, что могло вызвать такое поведение? Может мне что-то не хватает в конфигурации?

Спасибо!

medium.com/dailyjs/… Идентификатор, если эта статья поможет кому-либо, но может быть полезна, удачи
Steve Bohmbach 03.10.2018 17:37

Стив, это был именно тот учебник, которому я следовал, но я не понимаю, почему я удалил часть подписки = S (хотя я заставил ее работать без нее в первый раз). Добавление подписки действительно решило мою проблему. Я уточню в ответе.

Thiago Loddi 03.10.2018 19:04

Я рад, что он решил это за вас.

Steve Bohmbach 03.10.2018 19:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
80
1

Ответы 1

Как Стив указал в комментариях, в руководстве по это объясняется, как правильно реализовать socket.io.

Похоже, мне не хватало подписки. Когда я его добавил, все заработало. Код теперь такой:

API:

import express from 'express';
import socketIo from 'socket.io';
import http from 'http';

const app = express();
const port = 3300;

const server = http.createServer(app);
const io = socketIo({ 
    serveClient: false,
    transports: [ 'websocket', 'polling' ],
    pingTimeout: 3000,
    pingInterval: 3000,
    allowUpgrades: false,
    upgrade: false,
    cookie: false
}).listen(server);

io.on('connection', function(socket){
    console.info("------------------------- CONNECTED!!!");
    socket.on('subscribeToName', () => { // <---- add this
        app.get('/change_name', (req, res) => {
            console.info("Change Name");
            const { name } = req.query;
            res.sendStatus(200);

            console.info('Emitting Event');
            socket.emit('name', name);
        }); 
    });
});

server.listen(port, err => err ? throw err : console.info("Server online. Listening to port " + port);

И в моем приложении React:

import React from "react";
import openSocket from 'socket.io-client';

export default class Header extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      name: "Thiago"
    };

    console.info("Open Socket");
    const socket = openSocket('http://localhost:3300', {
      transports: [ 'websocket', 'polling' ],
    }); 
    console.info("Set event listener");
    socket.on('name', name => {
      console.info('receiving event')
      this.setState({ name });
    });
    console.info("Subscribe to Listener");
    socket.emit('subscribeToName'); // <---- add this
  }

  render() { /* ... */ }
}

Но это приводит к другим вопросам:

  1. Почему без подписки сокет работал после перезапуска сервера?

  2. Теперь проблема перевернулась. В первый раз он работает нормально, но если сервер перезагружается, браузер снова подключается, но не подписывается повторно. Есть ли способ автоматически повторно подписаться на событие после переподключения браузера?

Спасибо!

Другие вопросы по теме