I am creating an express server which will cause the index.html page to redirect to a new page on receiving a post request. Everything works fine, but only for the first time. I have to restart the server regularly for it to work. Here are some code snippets.
//server.js
const app = express();
app.use(express.static(`${__dirname}/public`));
const server = http.createServer(app);
const io = socketIo(server, {'force new connection': true });
io.on('connection', (socket) => {
console.log('New client connected');
app.post('/redirect', (req,res) => {
socket.emit('redirect');
res.status(200).send('Redirected');
});
});
<body>
<!-- Jquery CDN -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<!-- Socket.IO -->
<script src="/socket.io/socket.io.js"></script>
<script>
let socket = io.connect({'force new connection': true });
socket.on('connect', () => {
console.log('Connected to Server');
});
socket.on('redirect', () => {
window.location.replace("https://google.com");
});
</script>
</body>
The main issue, is that you have your route inside the socket connection listener. A route should be only registered once. And connection is triggered multiple times.
const app = express();
app.use(express.static(`${__dirname}/public`));
const server = http.createServer(app);
const io = socketIo(server, {'force new connection': true });
app.post('/redirect', (req,res) => {
res.status(200).send('Redirected');
io.emit('redirect');
// io.to(someSocketOrRoom).emit('redirect');
});
io.on('connection', (socket) => {
console.log('New client connected');
});
If you want to emit to the socket when you receive a message from outside the socket, in this case an HTTP Post. You need to use io.emit to emit to all sockets, or io.to().emit to emit to a specific one.
Now, it doesn't make much sense to redirect using socket.io, if you're posting to /redirect why don't you just redirect the user using res.redirect, without emitting anything.
Related
I'm having issues with Node SocketIo client not emitting data. So when the client connects in the index.html does log the "Connected This Is A Test", however it does not socket.emit('cool'), no errors nor does it seem to log on server.js. I'm not sure why its not emitting or the server isnt listening.
Server.js
const path = require('path');
const http = require('http');
const express = require('express');
const socketio = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketio(server);
const PORT = 3002;
app.use(express.static(path.join(__dirname, 'public')));
// run when client connects
io.on('connection', () => {
console.log('New WS connection...');
io.emit('connection', 'This Is A Test');
});
io.on('cool', (msg) => {
console.log(msg);
});
server.listen(PORT, () => console.log(`server running on port ${PORT}`));
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on('connection', function(data){
console.log("connected", data);
socket.emit('cool', 'MSG');
});
</script>
</body>
</html>
On your server, you need to be listening for the cool message on a specific connected socket, not on the io object. The io object does not have specific socket messages other than announcing a newly connected socket. To listen for messages from a specific socket, you need a listener on the connected socket itself. The usual place to add that listener is in the connection event where you are presented with the newly connected socket object.
So change this:
// run when client connects
io.on('connection', () => {
console.log('New WS connection...');
io.emit('connection', 'This Is A Test');
});
io.on('cool', (msg) => {
console.log(msg);
});
to this:
// run when client connects
io.on('connection', (socket) => {
console.log('New WS connection...');
// send a test event back to the socket that just connected
socket.emit('test', 'This Is A Test');
// listen for the cool message on this new socket
socket.on('cool', (msg) => {
console.log(msg);
});
});
Also, you really should not be emitting event names used by the system like connection. That's why I changed the event name to test so it won't conflict with names that socket.io itself is using.
I am trying to build a node server which as a middleman for my website. Several libraries are used.
Axios, I use axios to post requests to API and get the data from database
Socket.io, I use socket.io for recording who login and broadcast the message to every user if needed.
Express, I use it to host my React web app.
For the web app, I use componentDidMount and Axios to fetch data when the page is started and pressed the login button respectively. However, not every time the node server response, I will say its freezed. Sometime I press "Esc", and it will response the message back. How can I make sure it returns every time? Thanks a lot!
Partial Code from node js:
server.js
#for access DB
const DBhttp = require('http');
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(morgan('common', { stream: serverLogStream}));
app.use('/api/login', loginRouter);
app.use('/api', router);
let DBserver;
DBserver = DBhttp.createServer(app)
#Express for host app
var AppServer;
var http;
var webApp = express();
webApp.use(express.static(path.join(__dirname, 'build')));
webApp.get('/', function(req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
AppServer= http.createServer(options, webApp);
#socket.io commumicate between app
const socketIO = require("socket.io");
var io = socketIO.listen(server);
var clients = {};
io.sockets.on('connection', function (socket) {
#do the communication
}
React
react_index.js
initializeSession(this.state.loginName); #connect socket
this.setState({isLogin:true});
axios.post(SERVER_NAME + 'api/afterLogin')
.then((res) => {
this.setState({
full_name : res.data,
})
return Promise.resolve('Success')
})
You can add one more client right on your server to connect it to the same channel and see all the responses.
You can write the simple index.html with alike code:
<!doctype html>
<body>
<ul id="messages"></ul>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script>
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
var socket = io.connect({'YOUR PATH TO SOCKET SERVER'});
socket.on('connect', () => {
console.log('socket.on connect');
});
socket.on('message', function (msg) {
$('#messages').append($('<li>').text(JSON.stringify(msg)));
});
socket.on('update', function (msg) {
$('#messages').append($('<li>').text(JSON.stringify(msg)));
});
socket.on('disconnect', () => {
console.log('socket.on disconnect');
})
</script>
</body>
On editing it as you need, you can enable it like this:
app.get('/socketIo', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
Now you can see all the responses, which your server sends to the address {YOUR PATH TO SERVER}/socketIo
Also it would be beneficial to add console.log, to get the information about the clients
io.clients((error, clients) => {
if (error) throw error;
console.log('clients ', clients);
});
This way you'll know whether your client is working
I am trying to implement chat application using nodejs and socket.io. The application works on localhost. But when I deploy same on my production server then socket.io can't make any connection.
Code for server.js
var express = require('express');
var app = express();
var socket = require('socket.io');
var chat_controller = require('./controllers/ChatController.js');
var user_controller = require('./controllers/UserController.js');
var Group_controller = require('./controllers/GroupChatController.js');
app.get('/search', function (req, res) {
user_controller.get(req, res);
});
app.get('/groupSearch', function (req, res) {
user_controller.get(req, res);
});
var server = app.listen(3600, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
var io = socket(server);
io.on('connection', (socket) => {
console.log('made socket connection', socket.id);
socket.broadcast.emit('userconnected');
chat_controller.respond(io, socket);
Group_controller.respond(io, socket);
user_controller.respond(io, socket);
});
io.on('disconnect', function () {
console.log('made socket disconnect', socket.id);
});
Code for client.js
var socket = io.connect('https://www.mywebsite.com', {
path: '/apichat'
});
/* Other events related to socket. */
As my server uses SSL I can't used IP:PORT directly so I am using ProxyPass as
ProxyPass /apichat http://127.0.0.1:3600
After all this still socket connection is not established between server and client.
Error shown in browser console is:
POST https://www.mywebsite.com/apichat/?EIO=3&transport=polling&t=MUc-TJK 404 (Not Found)
And in browser Network tab it shows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /</pre>
</body>
</html>
I have checked many other questions posted here and other sites but no question address this issue.
Please Help.
The issue you are encountering is probably due to ssl enabled on your website.
You need to pass ssl related files in your app.js file. Sample code for this is as follow:
var fs = require('fs');
var options = {
key: fs.readFileSync('PATH_TO_SSL_KEYS.key'),
cert: fs.readFileSync('PATH_TO_SSL_CERTS.crt'),
ca: fs.readFileSync('PATH_TO_SSL.pem')
};
var app = require('https').createServer(options, handler), io = require('socket.io').listen(app);
io.set('transports', [
'websocket',
'flashsocket',
'htmlfile',
'xhr-polling',
'jsonp-polling',
'polling'
]);
function handler(req, res) {
res.writeHead(200);
res.end("welcome sir!");
}
var chat_controller = require('./controllers/ChatController.js');
var user_controller = require('./controllers/UserController.js');
io.sockets.on('connection', function (socket) {
socket.broadcast.emit('userconnected');
chat_controller.respond(io, socket);
user_controller.respond(io, socket);
socket.on('message', function (data) {
socket.broadcast.emit('message', data);
});
});
io.on('disconnect', function (socket) {
console.log('made socket disconnect', socket.id);
});
app.listen(3300);
Try editing your application file as per above mentioned sample code and then try to use it. If you can't get path to ssl related file, then you need to contact either your system administrator or the hosting provider.
I hope it helped.
I am trying to show a component when someone goes to /videocall on the React side of my application.
<BrowserRouter>
<Route path="/videocall" component={VideoCall} />
</BrowserRouter>
and here's how someone can go to that route through a button click from a different component.
<Link to='/videocall'>
Go to Video Call
</Link>
And up until here it's working fine. I can see my new VideoCall component.
But I also want this route handler on the Node/Express side of my application so I can start a Socket.io server.
Since React and Express rendering are different so express doesn't know how to handle /videocall.
I am using it like below.
const socketIO = require('socket.io');
module.exports = (app, server) => {
app.get('/api/videocall', (req, res) => {
const io = socketIO(server);
io.on('connection', (socket) => {
console.log('User connected');
socket.on('message', (msg) => {
console.log(msg);
});
socket.on('disconnect', () => {
console.log('User disconnected');
});
});
});
}
And I am using a wildcard route match that will render the default index.html file like so:
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
And it's working fine. When I go to /videocall from the URL I get routed to my VideoCall component.
But the client is only getting connected to the socket server when I go to /api/videocall and not when I go to /videocall.
How do I resolve that since I want the client to get connected to the socket server when he goes to VideoCall component from a different component on the front end like so:
<Link to='/videocall'>
Go to Video Call
</Link>
So, I finally managed to make it work.
Here's how I did it.
I wrote my socket code in my index.js file and not in any route handler.
const socket = require('socket.io');
const PORT = process.env.PORT || 5000;
const server = app.listen(PORT);
const io = socket(server);
io.on('connection', (socket) => {
console.log('User connected');
socket.on('message', (msg) => {
console.log(msg);
});
socket.on('disconnect', () => {
console.log('User disconnected');
});
});
And in my VideoCall component I wrote my connect method inside componentDidMount lifecycle method. So now I am only connecting when I go that /videocall route.
import io from 'socket.io-client';
var socket;
class VideoCall extends Component {
componentDidMount() {
socket = io('http://localhost:5000');
}
}
I'm trying out Websockets/Node.js/Socket.io/Express for the first time and I'm trying to create a simple chat program. Everything runs fine and I see both clients in my node termial.
But when I try to execute my socket.send(), I get an error in Firefox (socket.send is not a function). It doesn't complain about socket.connect() so I know the socket.io.js is loaded.
Here is my server code:
var sys = require('util');
var express = require('express');
var io = require('socket.io');
var app = express.createServer();
app.listen(8080);
app.use(express.static(__dirname));
app.get('/', function (req, res) {
res.render('index.html', {
title: 'Chat'
});
});
var socket = io.listen(app);
socket.on('connection', function (client) {
client.on('message', function (message) {
console.log("Message: " + JSON.stringify(data));
socket.broadcast(message);
});
client.on('disconnect', function () {});
});
My client code:
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
var socket = new io.Socket("http://localhost:8080");
socket.connect();
Then I do some code to get the chat message and send it.
socket.send(JSON.stringify(values));
Explanations
You haven't initialized Socket.io correctly on the server-side and client-side.
Client Side
new io.Socket("http://localhost:8080"); doesn't give you the object that you want, you need new io.connect("http://localhost:8080");.
You need to wait until the client is connected to the server before sending a message.
Server side
socket is the object send back by Socket.IO, you need to use socket.sockets to have access to on.
To broadcast a message, you need to use the client object like this: client.broadcast.send()
The variable data doesn't exist on your broadcast. You probably mean message.
Solution
Server
var sys = require('util'),
express = require('express'),
io = require('socket.io'),
app = express.createServer();
app.listen(8080);
app.use(express.static(__dirname));
app.get('/', function (req, res) {
res.render('index.html', {
title: 'Chat'
});
});
var io = io.listen(app);
io.sockets.on('connection', function (client) {
client.on('message', function (message) {
console.log("Message: " + JSON.stringify(message));
client.broadcast.send(message);
});
client.on('disconnect', function () {});
});
Client
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
<script>
var socket = new io.connect("http://localhost:8080"),
connected = false;
socket.on('connect', function () {
connected = true;
});
// Use this in your chat function.
if (connected) {
socket.send(JSON.stringify(values));
}
</script>
socket.broadcast(message); should be io.sockets.emit('key', message);
when you use the socket object passed in threw the connect event your only emitting information to that client, to emit to all clients you have to use io.sockets.emit().
also with socket.send(JSON.stringify(values)); I think you want to do socket.emit(namespace, data);
see my connection file from one of my projects here: https://github.com/AdminSpot/HangoutCanopy/blob/master/javascripts/connection.js
You have to wait for socket.io to connect on the client side
var socket = new io.Socket("http://localhost:8080");
socket.connect();
socket.on('connect', function() {
socket.emit('event', data);
});