Wednesday, October 27, 2021

[SOLVED] Socket.io is not working after deployment - throwing an error - 405 (Not Allowed)

Issue

Building an application with Angular and Node. Integrating a chat application built with Socket.io. Working fine when tested locally. Even after deploying the Node JS backend to the server machine (AWS EC2 Instance), Our local angular app can access the backend server. But after deploying the angular application in EC2, the chat module is not working and throwing an error " POST https://mysitedotcom/socket.io/?EIO=3&transport=polling&t=MzNa0m- 405 (Not Allowed) " Please find the server side code below.

require('./global_constants');

const Knex = require('knex');
const morgan = require('morgan');
const express = require('express');
const bodyParser = require('body-parser');
const promiseRouter = require('express-promise-router');
const rs = require('rocket-store');
const knexConfig = require('./knexfile');
const registerApi = require('./api');
const adminName = require('./config/config').admin.name;
const dbObj = require('./controllers/dbConn');
const cleaner = require('./controllers/textCleaner');
const fs = require('fs');
const rimraf = require('rimraf');
const socketIO = require('socket.io');
const db = dbObj.db;

const {
  Model
} = require('objection');
const cors = require('cors');

const knex = Knex(knexConfig[process.env.NODE_ENV || 'production']);

Model.knex(knex);

const router = promiseRouter();

const app = express()
  .use(bodyParser.json())
  .use(morgan('dev'))
  .use(cors(
    {
      credentials: true,
      origin: ['http://localhost:4200', 'http://localhost:4201']
    }
  ))

app.use('/api/', router).set('json spaces', 2);

app.use((req, res, next) => {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
})


registerApi(router);

app.use((err, req, res, next) => {
  if (err) {
    console.error(err);
    res.status(err.statusCode || err.status || 500).send(err || {});
  } else {
    next();
  }
});

const http = require('https').createServer(app);
const io = socketIO(http);
http.listen(3000, function () {
  console.log('listening on *:3000');
});

rs.options({
  data_storage_area: "./msg",
  data_format: rs._FORMAT_JSON,
});


io.on('connection', socket => {
  socket.on('new-user', async (room, userId) => {
    // some logic goes here
  })

  socket.on('new-message', async (room) => {
    // Some logic
  })

  socket.on('user-disconnect', async (room, userId) => {
    // Some logic
  })
})

Please find the Client side code below

import { Injectable } from '@angular/core';
import * as io from 'socket.io-client';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ChatService {

  private socket;
  constructor() {
    this.socket = io();
  }

  public newUser(roomName, id) {
    this.socket.emit('new-user', id, roomName);
  }
  public userDisconnected(roomName,id){
    this.socket.emit('user-disconnect',roomName,id)
  }

  public sendMessage(roomName, message,fullname,) {
    this.socket.emit('new-message',roomName,message,fullname);
  }

  public getconnect = () =>{
    return Observable.create((observer) => {
      this.socket.on('user-connected', (message,prev,socketId,flag) => {
          observer.next({msg:message,all_prev_msg:prev,socketId:socketId});
      });
    });
  }
  public getDisconnected = () =>{
    return Observable.create((observer) => {
      this.socket.on('user-disconnected', (message) => {
          observer.next(message);
      });
    });
  }

  public getMessages = () => {
    return Observable.create((observer) => {
      this.socket.on('new-message', (room,message,userId) => {
          observer.next({text:message,sender:userId});
      });
    });
  }

}

Please let me know if anyone has any more questions. Many thanks.


Solution

Looks like you have nginx in your ec2 server, if yes you need to have the config below

location /static {
    try_files $uri =404;
}

location /socket.io {
        proxy_pass http://node;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        add_header  Front-End-Https   on;
}

error_page 405 @nodejs;


Answered By - AWS PS