【问题标题】:How to implement socket.io Mean Stack application (Chat - APP) Properly?如何正确实现 socket.io 平均堆栈应用程序(聊天 - APP)?
【发布时间】:2022-01-27 02:36:16
【问题描述】:

我正在使用平均堆栈来制作聊天应用程序,API REST 与 app.listen() 一起工作正常,我需要一种方法来检测何时创建和发送消息。我阅读了有关 socket.io 的信息,并尝试在我的应用程序中实现它,但我不断收到以下消息:
GET http://localhost:4200/socket.io/?EIO=4&transport=polling&t= NwEn1gL 404(未找到)我不知道错误是在客户端还是在服务器端。

INDEX JS(服务器端)

const express = require('express');
const session = require('express-session');
const dotenv = require('dotenv');

const { createServer } = require("http");
const { Server } = require("socket.io");

const MongoDbSession = require('connect-mongodb-session')(session);
const path = require('path');

const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {cors: {origin: 'http://localhost:4200', methods: ['POST', 'GET']}, transports: ['websocket']});

const port = process.env.PORT || 3000;


if (process.env.NODE_ENV !== 'production') {
    dotenv.config();
}

/* DB CONNECTION */

/* Sessions Mongo */
const store = new MongoDbSession({
    uri: process.env.MONGO_URI_USERS,
    collection: "mySessions",
});

/* URLs Domain */
var UrlDomain;

if(process.env.NODE_ENV === "development")
{
    UrlDomain = 'http://localhost:4200';
}
else if(process.env.NODE_ENV === "production")
{
    UrlDomain = 'https://blue-chat-app.herokuapp.com';
}

/* MONGODB MODELS */

const users = require('./routes/users');
const contacts = require('./routes/contacts');
const messages = require('./routes/messages');
const chats = require('./routes/chats');


/* ENABLING MIDDLEWARES */

app.use((req, res, next) => // CORS MIDDLEWARE
{ 
    res.header('Access-Control-Allow-Credentials', true);
    res.header("Access-Control-Allow-Origin", UrlDomain); // update to match the domain you will make the request from
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Access-Control-Allow-Headers, Access-Control-Request-Method, Access-Control-Request-Headers");
    res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, PATCH, PUT, OPTIONS');
    next();
});
 
    /* Middleware Parser */
    
app.use(express.json());
app.use(express.urlencoded({extended: true}));

    /* Express session Middleware */

app.use(session({
    secret: 'Key that will sign cookie',
    resave: false,
    saveUninitialized: false,
    store: store
}));
  

/* STATIC ROUTE FOLDERS */

app.use(express.static('public')); // Set Static Folder

app.use('/images', express.static(path.join('images'))); // Set Images Path


/* APP ROUTES */
app.use('/api/users', users);
app.use('/api/contacts', contacts);
app.use('/api/messages', messages);
app.use('/api/chats', chats);  

/* Socket Configuration */
io.on('connection', (socket) => {
    console.log('a user connected');
    socket.on('disconnect', () => {
      console.log('user disconnected');
    });
    socket.on('save-message', (data) => {
        console.log(data);
        io.emit('new-message', { message: data });        
    });
});


/* APP CONFIGURATION */

 httpServer.listen(port, () => {
    console.log("Server listening on port: ", port);
});

角组件(客户端)

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import {io} from 'socket.io-client';
import { ChatService } from 'src/app/services/chat.service';

@Component({
  selector: 'app-blu',
  templateUrl: './blu.component.html',
  styleUrls: ['./blu.component.scss']
})
export class BluComponent implements OnInit {

  ContactList!: any[];
  Chats!: any[];
  Messages!: any[];

  SelectedChat!: any;
  Chat!: any;

  User!: any;

  socket = io('http://localhost:3000', {withCredentials: true, transports: ["websocket"]});

  constructor(private chatService: ChatService, private route: ActivatedRoute) { }

  ngOnInit(): void {
    if(localStorage.getItem('user'))
    {
      this.User = JSON.parse(localStorage.getItem('user') || '');
    }

    this.getAllChats();

    this.route.params.subscribe((params: Params) => {
      if(params['id'])
      {
        this.SelectedChat = params['id'];
        this.getAllMessages(params['id']);
        this.getChatByID(params['id']);
      }
    });

    this.getNewMessages();
    
  }

  getAllChats()
  {
    this.chatService.getAllChats().subscribe((chats: any) => {
      if(chats)
      {
        this.Chats = chats;
        console.log(chats);

        this.Chats = this.Chats.filter(chat => (chat.user._id === this.User._id) || (chat.contact._id === this.User._id));        
      }
    });

  }

  getChatByID(id: string)
  {
    this.chatService.getChatByID(id).subscribe((chat: any) => {
      this.Chat = chat;
    });    
  }

  getAllMessages(id: string)
  {
    this.chatService.getAllMessages().subscribe((messages: any) => {
      this.Messages = messages;

      this.Messages = this.Messages.filter(message => (message.sender._id === this.User._id || message.receiver._id === this.User._id) && message.chat._id === id);
    });
  }

  sendMessage(message: string)
  {
    this.chatService.sendMessage(this.User._id, this.Chat.contact._id, message, this.Chat._id).subscribe(message => {
      this.socket.emit('save-message', `Message - Sent by: ${this.User._id}`);
      this.ngOnInit();
    });
  }

  getNewMessages()
  {
    this.socket.on('new-message', () => {
      this.getAllMessages(this.Chat._id);
    });
  }
}

【问题讨论】:

    标签: javascript node.js express socket.io


    【解决方案1】:

    仔细阅读文档后,我发现我缺少允许标头以建立连接:

    所以改变:

    const io = new Server(httpServer, {cors: {origin: 'http://localhost:4200', methods: ['POST', 'GET']}, transports: ['websocket']});
    

    到:

    const io = new Server(httpServer, {cors: {origin: 'http://localhost:4200', allowedHeaders:["Access-Control-Allow-Origin"], credentials:true}, transports: ['websocket']});
    

    【讨论】: