Angular and Node.js Socket IO Issue

1.7k views Asked by At

I'm trying to send messages from an Angular front end to a Node.js server. I'm using socket.io and Node.js as my server, and running an Angular front end using the ngx-socket-io module. I followed the examples but I'm getting this error:

http://localhost:3000/socket.io/?EIO=3&transport=polling&t=NPDJPOe (POST Request)

{"code":2,"message":"Bad handshake method"}

Here is my game.service file:

import { Injectable } from '@angular/core';
import { Socket } from 'ngx-socket-io';

@Injectable()
export class GameService extends Socket {

    sentence = this.socket.fromEvent<string>('resp');

    constructor(private socket: Socket) {
    super({ url: 'http://localhost:3000', options: {} });
     }

    send(type: number, words: string): void {

        var num = new Number(type);
        var say = 'say' + num.toString();
        console.log("in service", say, words);
        this.socket.emit(say, words);
    }
}

And here is my game.component file:

import { GameService } from '../game.service';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-game',
  templateUrl: './game.component.html',
  styleUrls: ['./game.component.css']
})
export class GameComponent implements OnInit, OnDestroy {

    message: string;
    messages: string[];
    text1: string = "";
    private newPhrase: Subscription;

  constructor(public gameService: GameService) { }

  ngOnInit(): void {
    this.newPhrase = this.gameService.sentence.subscribe(sentence => this.message = sentence);
  }

  ngOnDestroy() {
    this.newPhrase.unsubscribe();
  }

  send(type: number): void {
    console.log(type, this.text1);
    this.gameService.send(type, this.text1);
  }

}

Here is my app.module file:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LineupComponent } from './lineup/lineup.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import {MatChipsModule} from '@angular/material/chips';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatSelectModule} from '@angular/material/select';
import {MatButtonModule} from '@angular/material/button';
import {MatRadioModule} from '@angular/material/radio';

import {DragDropModule} from '@angular/cdk/drag-drop';

import { HttpClientModule } from '@angular/common/http';
import { GameComponent } from './game/game.component';

import { SocketIoModule, SocketIoConfig } from 'ngx-socket-io';

const config: SocketIoConfig = { url: 'http://localhost:3000', options: {} };

@NgModule({
  declarations: [
    AppComponent,
    LineupComponent,
    GameComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatChipsModule,
    MatFormFieldModule,
    MatSelectModule,
    MatButtonModule,
    MatRadioModule,
    DragDropModule,
    HttpClientModule,
    SocketIoModule.forRoot(config)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Here is my NodeJS file (app.js):

const http = require('http').Server(app);
const cors = require('cors');

const io = require('socket.io')(http, { cors: {
    origin: "http://localhost:4200",
    methods: ["GET", "POST"],
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true
  }});

app.get('/', (req, res) => {

  res.sendFile(__dirname + '/index.html');

});

io.on('connection', (socket) => {

  console.log('a user connected');
  
  socket.on("say1", words => {
        
    console.log('message: ' + words);
    socket.emit("resp", words);

  });

    socket.on("say2", words => {
    
    console.log('message: ' + words);
    socket.emit("resp", words + "+" + words);

  });
});


http.listen(3000, () => {
  console.log('listening on *:3000');
});

package.json:

{
  "name": "baseball",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~10.0.11",
    "@angular/cdk": "^10.1.3",
    "@angular/common": "~10.0.11",
    "@angular/compiler": "~10.0.11",
    "@angular/core": "~10.0.11",
    "@angular/forms": "~10.0.11",
    "@angular/material": "^10.1.3",
    "@angular/platform-browser": "~10.0.11",
    "@angular/platform-browser-dynamic": "~10.0.11",
    "@angular/router": "~10.0.11",
    "ngx-socket-io": "^3.2.0",
    "rxjs": "~6.5.5",
    "simple-peer": "^9.8.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.10.3"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^0.1002.0",
    "@angular/cli": "~10.0.7",
    "@angular/compiler-cli": "~10.0.11",
    "@types/jasmine": "~3.5.0",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "^12.11.1",
    "codelyzer": "^6.0.0",
    "jasmine-core": "~3.5.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~5.0.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~3.0.2",
    "karma-jasmine": "~3.3.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "tslint": "~6.1.0",
    "typescript": "~3.9.5"
  },
  "description": "This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.0.7.",
  "main": "index.js",
  "repository": {
    "type": "git",
    "url": "git+https://[email protected]/jking72/baseball-ui-angular.git"
  },
  "author": "Jon King",
  "license": "ISC",
  "homepage": "https://bitbucket.org/jking72/baseball-ui-angular#readme"
}

Node is working, it says 'listening on *:3000', and everything seems to be working in Angular

1

There are 1 answers

0
Lucho On

From the code you posted it seems you'r not authenticating from the client or is something missing in the post?

Else you should apply the basic part from the client-side required for the Content-type Authorization with a dummy like this in your GameService instead:

super({ url: 'http://localhost:3000', 
        options: {
          extraHeaders: { Authorization: "Bearer authorization_token_dummy" } 
        }
      });