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');
}
}
Related
There is http module to create a server and passing express app context to it and then listening to it.
I've seen express' app.listen returns a Server context
Now how to create a socket.io server using app.listen's context
I've tried the below code but it is not working.
onst express = require('express')
const socket = require('socket.io')
const PORT = 5000
const app = express()
const server = app.listen(PORT, () => console.log(`Server started on port ${PORT}`))
const io = new socket.Server(server)
io.on("connection", function(socket) {
console.log("A new socket has joined: " + socket.id)
socket.on("hello", function(data) {
console.log(data);
})
})
Code starts without throwing any error but the socket server is not starting
Are you sure your socket server is not starting? May be you have a problem on client side...
I'm added index.html with client code and it connected to backend successfully.
Checkout: https://github.com/theanurin/stackoverflow.68511005
P.S.
Server started on port 5000
A new socket has joined: IqEjjc0dBHYSHqpMAAAB
Socket IO's documentation has a section on integrating with Express. Their example code looks like this:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
While still using the http module directly, you could perhaps replace http.createServer(app) with your app.listen call. Mind you, I'm pretty sure that app.listen actually uses http.createServer under the hood. According to their documentation they do.
I made a connection with react native 'socket.io-client', your code worked to me
Here is my react native code
import React,{ Component } from "react";
import {View,TextInput,Text,StyleSheet} from 'react-native'
import io from "socket.io-client";
export default class ChatApp extends Component{
constructor(props) {
super(props);
this.state = {
chatMessage: "",
chatMessages: []
};
}
componentDidMount() {
this.socket = io("http://127.0.0.1:5000");
this.socket.on("hello", msg => {
this.setState({ chatMessages: [...this.state.chatMessages, msg]
});
});
}
submitChatMessage() {
this.socket.emit('hello', this.state.chatMessage);
this.setState({chatMessage: ''});
}
render() {
const chatMessages = this.state.chatMessages.map((chatMessage,index) => (
<Text key={index} style={{borderWidth: 2, top: 500}}>{chatMessage}</Text>
));
return (
<View style={styles.container}>
{chatMessages}
<TextInput
style={{height: 40, borderWidth: 2, top: 500}}
autoCorrect={false}
value={this.state.chatMessage}
onSubmitEditing={() => this.submitChatMessage()}
onChangeText={chatMessage => {
this.setState({chatMessage});
}}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
height: 400,
flex: 1,
},
});
I am developing a simple app with SocketIO and I am encountering this problem. In the server I have the following code:
const httpServer = require('http').createServer();
const socketIO = require('socket.io');
const port = process.env.PORT_WS || 5001;
const io = socketIO(httpServer, { cors: { origin: '*' } });
io.on('connection', (socket) => {
console.log('Connected to socket');
socket.on('join-room', () => {
console.log('joined room')
});
});
httpServer.listen(port, () => {
console.log(`Listening on the port ${port}`);
});
In the client I have the following code:
import { io } from 'socket.io-client';
export default class SocketConnection {
constructor() {
this.initializeSocketConnection();
this.initializeSocketEvents();
}
initializeSocketConnection() {
console.log('I am here');
this.socket = io('ws://localhost:5001');
}
initializeSocketEvents() {
this.socket.on('connect', () => {
console.log('Socket connected');
});
}
}
I get in the console two Socket connected messages.
This is not a re-render issue because the I am here message is logged only once.
I am using socket.io version 4.0.1 both in the client and in the backend.
So this is happening because, in React Strict Mode, constructors are called two times. React seems to hide this. As the console.log('Socket connected'); is inside an "on" event, React has no way to "hide" this. Thus, 'I am here' is going to be shown once but 'Socket connected' is going to be shown twice.
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 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.
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.