So first I would like to say that I have looked at many other answers that were given for similar questions, but none worked for me.
My setup is a node js server and a react js client. And I am having trouble doing just a basic setup. Any one who would help me out here, I really appreaciate.
And also on the client code I have alternated through different options for serverUrl from localhost with the http http://localhost:6000 and without localhost:6000. Same for ip address.
NODE JS Server Code
const express = require('express');
const app = express();
const users = require("./routes/api/users");
const profile = require("./routes/api/profile");
const project = require("./routes/api/project");
const auth = require("./routes/api/auth");
const email = require("./routes/api/email");
app.use(express.static(__dirname + '/public'));
const server = require('http').createServer(app);
const io = require('socket.io')(server);
io.on('connection', (socket)=> {
console.log("user connected")
socket.on('SEND_MESSAGE', function(data){
console.log("message received")
io.emit('RECEIVE_MESSAGE', data);
})
});
//*** Start of Routes ***//
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "http://localhost:6000");
res.setHeader("Access-Control-Allow-Credentials", "true");
next();
})
app.use("/api/users", users);
app.use("/api/profile", profile);
app.use("/api/auth", auth);
app.use("/api/project", project);
app.use("/api/email", email);
//*** End of Routes ***//
const port = 6000;
server.listen(port, () => {
console.log(`Server Running at ${port}`);
});
REACT JS Client Code
import React,{useEffect,useState,useRef} from 'react';
import io from "socket.io-client";
class App extends React.Component {
constructor(props){
super(props);
this.state = {
username: 'name',
message: 'hello world',
messages: []
};
this.serverUrl = '127.0.0.1:6000';
this.socket = io(this.serverUrl, {reconnect: true});
this.setupSocket();
}
setupSocket() {
this.socket.on('connection', (data) => {
console.log(`Connected: ${data}`);
});
}
render(){
return(<p>Hello<p>)
}
}
export default App
It may have a problem with your socket server you can change your port and check if it is working
Related
Hello everyone and happy holidays!
I'm creating a chat app using socket.io and Express and need some guidance on how to proceed.
As it is now, I have my socket.io module in the same file as my express js file.
And it works fine, but when I started to implement a login page i noticed that when a go to the "localhost:port/" i still get connected to the socket and i get assigned a socket.id.
And it does make sense, I suppose, to start from the top and go to the bottom.
My plan is:
Go through the login page first
Then get redirected to the "localhost:port/MessagingClient" and get a socket.id
How it works now:
Go to the login page, get assigned a socket.id without login in.
Go to "localhost:port/MessagingClient" and get assigned a new socket.id
But since i run everything in 1 js file it doesn't work as i want it to.
My question is how can I split "Login" page and "MessagingClient" page, but still run on the same port?
I imagine I could solve this by running 2 node js processes instead of 1 and use 2 ports, but is that a valid way of doing it?
MessaginServer.js:
const dotenv = require("dotenv").config();
const express = require("express");
const app = require("express")();
const http = require("http").Server(app);
const io = require("socket.io")(http);
const port = process.env.PORT || 3000;
// import { readFromDB } from "./mongoDB.js";
const { readFromDB } = require("./mongoDB");
app.use(express.static(__dirname + "/public/"));
app.get("/", (req, res) => {
res.sendFile(__dirname + "/Public/LoginClient.html");
});
app.get("/MessagingClient", (req, res) => {
res.sendFile(__dirname + "/Public/MessaginClient.html");
});
io.on("connection", async (socket) => {
// socket.on("test1", arr1, arr2)=>{};
// socket.on("test2", arr1, arr2)=>{};
})
http.listen(port, () => {
console.log(`Socket.IO server running at http://localhost:${port}/`);
});
What i have tried:
I tried to move all the socket.io code inside
app.get("/MessagingClient", (req, res) => {
res.sendFile(__dirname + "/Public/MessaginClient.html");
});
but that resulted in message duplication..
Then I thought about trying to use Npm concurrently, but could not find anything about whether it is okay to use it in a production environment.
Any tips?
you create a socket server in a separate file:
const socketServer = (server) => {
const io = require("socket.io")(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});
//set middleware for socket server here before .on
io.use((socket, next) => {
yourMiddleware(socket, next);
});
// your io connection logic
io.on("connection", async (socket) => {
// socket.on("test1", arr1, arr2)=>{};
// socket.on("test2", arr1, arr2)=>{};
});
};
module.exports = {
socketServer,
};
then in app.js
//initialize app
const app = express();
// add your middlewares and routing
const server = http.createServer(app);
// import socketServer
socketServer(server);
server.listen(PORT, () => {
console.log(`Server is listening on ${PORT}`);
});
you create a socket server in a separate file:
const socketServer = (server) => {
const io = require("socket.io")(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});
//set middleware for socket server here before .on
io.use((socket, next) => {
yourMiddleware(socket, next);
});
// your io connection logic
io.on("connection", async (socket) => {
// socket.on("test1", arr1, arr2)=>{};
// socket.on("test2", arr1, arr2)=>{};
});
};
module.exports = {
socketServer,
};
then in app.js
//initialize app
const app = express();
// add your middlewares and routing
const server = http.createServer(app);
// import socketServer
socketServer(server);
server.listen(PORT, () => {
console.log(`Server is listening on ${PORT}`);
});
The problem is as the title suggests. When I run my app locally, I'm able to retrieve information from MongoDB but on Heroku, undefined is returned. Should I connect to MongoDB in another way because if I hardcode some text everything works just fine. Here are my scripts:
function to get data
const MongoClient = require("mongodb").MongoClient;
const dbConnectionUrl = "mongodb+srv://xxxxxxx#cluster0.ro4dz.mongodb.net/data?retryWrites=true&w=majority";
const saySomething = (req, res, next) => {
// res.status(200).json({
// body: 'Hello from the server!'
// });
login()
.then(val=>res.send(val))
};
async function login(){
const client = new MongoClient(dbConnectionUrl)
try{
await client.connect();
const database = client.db("data");
const movies = database.collection("movies");
const query = { name: "toke" };
const movie = await movies.findOne(query);
return movie
}catch(err){
console.log(err)
}
}
module.exports.saySomething = saySomething;
router
const express = require('express');
const router = express.Router();
const controllers = require('./../controllers/controllers');
router.get('/say-something', controllers.saySomething);
module.exports = router;
server
// Import dependencies
const express = require('express');
const cors = require('cors');
const path = require('path');
// Create a new express application named 'app'
const app = express();
// Set our backend port to be either an environment variable or port 5000
const port = process.env.PORT || 5000;
// This application level middleware prints incoming requests to the servers console, useful to see incoming requests
app.use((req, res, next) => {
console.log(`Request_Endpoint: ${req.method} ${req.url}`);
next();
});
// Configure the CORs middleware
// Require Route
app.use(cors());
const api = require('./routes/routes');
// Configure app to use route
app.use('/api', api);
// This middleware informs the express application to serve our compiled React files
if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging') {
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', function (req, res) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
};
// Catch any bad requests
app.get('*', (req, res) => {
res.status(200).json({
msg: 'Catch All'
});
});
// Configure our server to listen on the port defiend by our port variable
app.listen(port, () => console.log(`BACK_END_SERVICE_PORT: ${port}`));
front
import { useEffect, useState } from 'react';
import './App.css';
import axios from 'axios'
function App(){
useEffect(()=>{
get()
})
const[text, settext] = useState('')
async function get(){
let request = await axios.get('/api/say-something')
console.log(request.data.name)
settext(request.data.name)
}
return(
<div>{text}</div>
)
}
export default App;
I solved the issue! The first thing I did was that I added MongoDB connection URI as an environmental variable in my app via Heroku. Secondly, I added an option in MongoDB so that the cluster can be accessed from any computer. By default, the access is set to the local computer so I added another IP, namely 0.0.0.0/0 to my cluster, and now everything works just fine.
I'm trying to add websockets to a server that's using angular universal. As far as I can tell, express is consuming my request before it gets to my sockets, but I could be wrong about that.
I get this error in chrome:
WebSocket connection to 'ws://localhost:4200/socket' failed: Connection closed before receiving a handshake response
and I get this error in firefox:
Firefox can’t establish a connection to the server at ws://localhost:4200/socket.
when I run a separate nodejs server without the angular code, the websockets work fine.
Here is the relevant part of my server.ts
import 'zone.js/dist/zone-node'
import { ngExpressEngine } from '#nguniversal/express-engine'
import * as express from 'express'
import { join } from 'path'
import { AppServerModule } from './src/main.server'
import { APP_BASE_HREF } from '#angular/common'
import { existsSync } from 'fs'
import * as WebSocket from 'ws'
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express()
const distFolder = join(process.cwd(), 'dist/CAHClone/browser')
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index'
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}))
server.set('view engine', 'html')
server.set('views', distFolder)
server.use(express.json())
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}))
// All regular routes use the Universal engine
server.get('*', (req, res, next) => {
if (req.url === '/socket') return next() // leave '/socket' open for the websockets
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] })
})
return server
}
function run() {
const port = process.env.PORT || 4000
// Start up the Node server
const expressApp = app()
const server = expressApp.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`)
})
// Websockets
const wss = setupWebsockets(server)
}
function setupWebsockets(server) {
const wss = new WebSocket.Server({ server, path: '/socket' })
wss.on('connection', ws => {
console.log('Client connected.')
ws.send({message: 'Hi there!'})
})
wss.on('message', msg => {
console.log('Client said: ' + msg.toString())
})
return wss
}
declare const __non_webpack_require__: NodeRequire
const mainModule = __non_webpack_require__.main
const moduleFilename = mainModule && mainModule.filename || ''
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run()
}
export * from './src/main.server'
And here is a server.js file that works without angular related code
const express = require('express')
const WebSocket = require('ws')
const { join } = require('path')
const { existsSync } = require('fs')
// The Express app is exported so that it can be used by serverless Functions.
function app() {
const server = express()
server.use(express.json())
server.use('*', (req, res, next) => {
if (req.url === '/socket') return next()
res.end('Hello, world!')
})
return server
}
function setupWebsockets(server) {
const wss = new WebSocket.Server({ server, path: '/socket' })
console.log('set up websocket server');
wss.on('connection', ws => {
console.log('Client connected.');
ws.send('Hi there!')
})
wss.on('message', msg => {
console.log('Client said: ' + msg.toString());
})
}
function run() {
const port = process.env.PORT || 4000
const expressApp = app()
const server = expressApp.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`)
})
// Websockets
const wsServer = setupWebsockets(server)
}
run()
Could anyone help me understand what part of angular universal is breaking my websockets, and how to fix it?
I ran into this issue with the 'ws' module and passing in an express server. Try creating your server with the 'http' module and pass it into both express and 'ws'. I also recommend taking care of any authorization that you are going to do in the 'upgrade' event if necessary.
Did you solve the matter with dev:ssr ?
It is indeed working fine with serve:ssr but the only way I made it work with dev:ssr in local development is by using a proxy from ws://localhost:4200/ws to ws://localhost:4000
{
"/ws": {
"target": "ws://localhost:4000",
"secure": false,
"ws": true
}
}
Se my question here : Angular Universal (ssr-dev-server) Setting or getting the random port of the express app in dev:ssr
I am trying to establish socket.io connection between nodejs and react-native. But unfortunately it is not working.
The issue is that client side do not get connected with server via sockets.
Here is nodejs (server-side) code
const express = require("express");
const http = require("http");
const app = express();
const server = http.createServer(app);
const socket = require("socket.io");
const io = socket(server);
server.listen(process.env.PORT || 8000, () => console.log('server is running on port 8000'));
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
io.on('connection', socket => {
console.log('connection')})
Here is react-native(client-side) code (trimmed)
import React from 'react'
import { Button } from 'react-native'
import io from 'socket.io-client';
const Room = props => {
const sock = useRef();
useEffect(() => {
sock.current = io.connect(<HOSTNAME>, {
forceNode: true,
transports: ['websocket'],
});
//to check if mobile connected to server
console.log('test');
console.log('check 11', sock.current.connected);
sock.current.on('connect', function() {
console.log('check 2', sock.current.connected);
});
});
}
When I try to connect I am not getting 'check 2' message in my console, which is to be printed on execution of sock.current.on('connect'....
Libraries used: react-native version:0.62.1, socket.io-client version:2.3.0 (client-side), socket.io version:2.3.0 (server-side)
I have an Angular/NodeJS app, with Socket.io support added in for some real-time features.
I wanted to add MongoDB and PassportJS support so I have migrated to the generator-angular-fullstack structure.
Suddenly, the Socket.io features don't work anymore.
One error I've found is that the client-side JS library served by Socket.io at http://localhost/socket.io/socket.io.js now returns the index.html page from my app instead.
That sounds like a routing problem, so here is my routing configurations:
lib/routes.js (NodeJS):
module.exports = function(app) {
// Server API Routes
app.get('/api/awesomeThings', api.awesomeThings);
app.post('/api/users', users.create);
app.put('/api/users', users.changePassword);
app.get('/api/users/me', users.me);
app.get('/api/users/:id', users.show);
app.post('/api/session', session.login);
app.del('/api/session', session.logout);
// All other routes to use Angular routing in app/scripts/app.js
app.get('/partials/*', index.partials);
app.get('/*', middleware.setUserCookie, index.index);
app.get('/:session', function(req, res) {
res.render('views/index.html', {
title: 'Weld Spark'
});
});
};
app/scripts/app.js (AngularJS):
angular.module('weld.common').config(function($routeProvider, $locationProvider, $httpProvider) {
$routeProvider
.when('/main', {
templateUrl: 'partials/main',
controller: 'MainCtrl'
})
.when('/login', {
templateUrl: 'partials/login',
controller: 'LoginCtrl'
})
.when('/signup', {
templateUrl: 'partials/signup',
controller: 'SignupCtrl'
})
.when('/settings', {
templateUrl: 'partials/settings',
controller: 'SettingsCtrl',
authenticate: true
})
.when('/:session', {
templateUrl: 'views/ui-editor/editor.html',
controller: 'weldEditorController'
})
.otherwise({
redirectTo: '/my-project'
});
$locationProvider.html5Mode(true).hashPrefix('!'); // TODO: Test and figure out how this works in IE
// Intercept 401s and 403s and redirect you to login
$httpProvider.interceptors.push(['$q', '$location', function($q, $location) {
return {
'responseError': function(response) {
if(response.status === 401 || response.status === 403) {
$location.path('/login');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
};
}]);
})
.run(function ($rootScope, $location, Auth) {
// Redirect to login if route requires auth and you're not logged in
$rootScope.$on('$routeChangeStart', function (event, next) {
if (next.authenticate && !Auth.isLoggedIn()) {
$location.path('/login');
}
});
});
Any ideas why the socket.io route is broken?
UPDATE: entire server.js:
// Init Express framework and Socket.io
var express = require('express'),
path = require('path'),
fs = require('fs'),
mongoose = require('mongoose'),
http = require('http'),
socketio = require('socket.io');
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
// Application Config
var config = require('./lib/config/config');
// Connect to database
var db = mongoose.connect(config.mongo.uri, config.mongo.options);
// Bootstrap models
var modelsPath = path.join(__dirname, 'lib/models');
fs.readdirSync(modelsPath).forEach(function (file) {
require(modelsPath + '/' + file);
});
// Populate empty database with sample data
require('./lib/config/dummydata');
// Passport Configuration
require('./lib/config/passport')();
// Init app and web server
var app = express();
var server = http.createServer(app);
// Init Socket.io server
var io = socketio.listen(server);
app.set('socket.io.log.level', process.env.SOCKET_IO_LOG_LEVEL || 1);
require('./lib/socket')(io, app.get('socket.io.log.level'));
// Heroku web socket workaround
// https://devcenter.heroku.com/articles/getting-started-with-nodejs
// https://devcenter.heroku.com/articles/using-socket-io-with-node-js-on-heroku
io.configure(function() {
io.set('transports', ['xhr-polling']);
io.set('polling duration', 10);
});
// Express settings
require('./lib/config/express')(app);
// Routing
require('./lib/routes')(app);
// Web: Start server
app.listen(config.port, function () {
console.log('Express server running on http://localhost:%d in %s mode', config.port, app.get('env'));
});
// Expose app
exports = module.exports = app;
Socket.io is listening to server with var io = socketio.listen(server);.
app is listening to the port, not server.
change
app.listen(config.port, function () {
console.log('Express server running on http://localhost:%d in %s mode', config.port,
app.get('env'));
});
to
server.listen(config.port, function () {
console.log('Express server running on http://localhost:%d in %s mode', config.port, app.get('env'));
});