I have a react app with a components
useEffect( () => {
const socket = io(process.env.REACT_APP_BACKEND_DEVELOPMENT_URL);
// dispatch( updateSocket({socket}) );
socket.on('connected' , async () => {
console.log( 'connected' );
});
socket.on("connect_error", (err) => {
console.log(`connect_error due to ${err.message}`);
});
},[])
And in node back end I have
var app = express();
const server = http.createServer(app);
const io = socketio( server , {
cors:{ origin: '*'},
});
io.on('connection', (stream) => {
console.log('someone connected!');
});
It is showing error 1. polling.js:334 GET http://localhost:4000/socket.io/?EIO=4&transport=polling&t=O3BfeYs 404 (Not Found)
2. Mainpage.jsx:78 connect_error due to xhr poll error
Tried to solve this by chaging transports option to 'websocket' (found in most troubleshooter ) doesn't worked well for me
Related
I'm implementing a chat feature with Socket.io in a React Native Expo app. The socket connects when opening the chat screen and sends a message to the client. It also receives a message from the client without issue. It isn't until I try to emit a message from the client to server, to then be received and sent back that I have the issue. I am using a text input and useState. The sendMessage function works as expected if I replace the useState data with a static string, but not with the updated state unless I save the client page and then hit send. Below is my code:
Client
// TestScreen.js (Client)
import { io } from 'socket.io-client';
import { NGROK_URL } from '../api/ngrok';
const TestScreen = () => {
const [currentMessage, setCurrentMessage] = useState('');
const [arrivalMessage, setArrivalMessage] = useState('');
const socket = io(NGROK_URL, { autoConnect: false });
const sendMessage = () => {
setArrivalMessage(currentMessage);
socket.emit('send_msg', {
to: 'Server',
from: 'Client',
message: currentMessage,
});
};
useEffect(() => {
socket.connect();
socket.on('welcome', (arg) => console.log(arg));
socket.emit('client', 'Hello from the client!');
socket.on('receive_msg', ({ message }) => {
console.log(`From receive msg: ${message}`);
});
return () => socket.disconnect();
}, []);
Server
// index.js (Server)
const PORT = process.env.PORT || 5000;
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: 'http://localhost:3000',
methods: ['GET', 'POST'],
},
});
const onSendMessage = (data) => {
console.log(data);
io.emit('receive_msg', data);
};
const onConnection = (socket) => {
console.log(`User Connected: ${socket.id}`);
// Send a message to the client
socket.emit('welcome', 'Hello from the server!');
// Receive message from the client
socket.on('client', (arg) => console.log(arg));
socket.on('send_msg', onSendMessage);
socket.on('disconnect', (reason) =>
console.log(`User disconnected due to ${reason}.`)
);
};
io.on('connection', onConnection);
httpServer.listen(
PORT,
console.log(
`Server is running in ${process.env.NODE_ENV} on port ${PORT}`.yellow.bold
)
);
My frontend service is running on netlify.
And backend is on heroku.
I am trying to make chatApp.
After I entered chatRoom press sending button below error message pop up on console log.
"Failed to execute 'send' on 'WebSocket': Still in CONNECTING state."
I guess
problem is below code.
client
created() {
this.channel = this.$route.query.channel || '';
this.$store.state.user.stateWebSocket = new WebSocket('ws://peaceful-ridge-59102.herokuapp.com:9999/ws');
// this.websocket = new SockJS('http://localhost:8080/ws/realtime');
this.websocket=this.$store.state.user.stateWebSocket;
this.websocket.onmessage = ({ data }) => {
const vo = JSON.parse(data);
if (vo.channel === this.channel) {
this.appendNewMessage(this.tempName, vo.message, vo.time);
}
};
this.websocket.onopen = (event) => {
console.log('open event..', event);
};
this.websocket.onerror = (event) => {
console.log('error', event);
};
this.websocket.onclose = (event) => {
console.log('close', event);
};
}
This is sever.js
const cors = require('cors');
const express = require('express');
const app = express();
const WebSocket = require('ws');
const PORT = 9999;
app.use(
cors({
origin: true,
credentials: true,
})
);
const server = app.listen(PORT, () => {
console.log(PORT, 'waiting unitil connects');
});
app.get('/', (req, res) => {
res.send('Hello World!');
});
const wss = new WebSocket.Server({ server, path: '/ws' });
wss.on('connection', (ws, req) => {
// connection
console.log('새로운 클라이언트 접속');
ws.on('message', (message) => {
// receiving message
const json = JSON.parse(message.toString());
json.time = Date.now()
message = JSON.stringify(json)
console.log(message.toString());
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message.toString());
}
});
// Runs when client disconnects
wss.on('disconnect', () => {
});
});
ws.on('error', (err) => {
// error
console.error(err);
});
ws.on('close', () => {
// close
console.log('Client close');
clearInterval(ws.interval);
});
});
some people say I am sending your message before the WebSocket connection is established.
I am newbie on JS plz help me~!
Assuming I want to run a custom next js server, and to accept websocket connections on that same server, how can I avoid clobbering the next js dev server hot reloading which is also using websockets on the same server...
const { createServer } = require('http')
const WebSocket = require("ws")
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = createServer((req, res) => handle(req, res, parse(req.url, true)))
// pass the same server instance that is used by next js to the websocket server
const wss = new WebSocket.Server({ server })
wss.on("connection", async function connection(ws) {
console.log('incoming connection', ws);
ws.onclose = () => {
console.log('connection closed', wss.clients.size);
};
});
server.listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://localhost:${port} and ws://localhost:${port}`)
})
})
I believe this server should work in the production built version, so that the websocket server is created on the same server instance used to handle next js requests, but when I try to do this, the hot module reloading stops working, and errors appear in the chrome dev tools console because websocket connections it expects to be handled by webpack are now being handled by my custom websocket server.
How can I somehow route websocket connections for dev server to next and webpack and others to my own handler?
I know I can run my websocket server on another port, but I want to run it on the same server instance and same port as next js.
So the trick is to create a websocket server with noServer property set to true, and then listen to the server upgrade event, and depending on the pathname, do nothing to allow next js to do it's thing, or pass the request on to the websocket server we created...
const wss = new WebSocket.Server({ noServer: true })
server.on('upgrade', function (req, socket, head) {
const { pathname } = parse(req.url, true);
if (pathname !== '/_next/webpack-hmr') {
wss.handleUpgrade(req, socket, head, function done(ws) {
wss.emit('connection', ws, req);
});
}
});
... all together something like this ...
const { createServer } = require('http')
const WebSocket = require("ws")
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = createServer((req, res) => handle(req, res, parse(req.url, true)))
const wss = new WebSocket.Server({ noServer: true })
wss.on("connection", async function connection(ws) {
console.log('incoming connection', ws);
ws.onclose = () => {
console.log('connection closed', wss.clients.size);
};
});
server.on('upgrade', function (req, socket, head) {
const { pathname } = parse(req.url, true);
if (pathname !== '/_next/webpack-hmr') {
wss.handleUpgrade(req, socket, head, function done(ws) {
wss.emit('connection', ws, req);
});
}
});
server.listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://localhost:${port} and ws://localhost:${port}`)
})
})
Here is my answer to create a webSocket server on Next.js by using an api route instead of creating a custom server.
/pages/api/websocketserverinit.js:
import { WebSocketServer } from 'ws';
const SocketHandler = async (req, res) => {
if (res.socket.server.wss) {
console.log('Socket is already running')
} else {
console.log('Socket is initializing')
const server = res.socket.server
const wss = new WebSocketServer({ noServer: true })
res.socket.server.wss = wss
server.on('upgrade', (req, socket, head) => {
console.log("upgrade", req.url)
if (!req.url.includes('/_next/webpack-hmr')) {
wss.handleUpgrade(req, socket, head, (ws) => {
wss.emit('connection', ws, req);
});
}
});
wss.on('connection', (ws)=> {
console.log("connection", ws);
ws.on('message', (data) => {
console.log('received: %s', data);
})
ws.send('something');
});
}
res.end()
}
export default SocketHandler
You will have to call the api route to start the websocket server from the client (or server init script):
fetch("http://localhost:3000/api/websocketserverinit")
And then connect to it:
const ws = new WebSocket("ws://localhost:3000")
Not super nice, but may be useful in some case
I have an Electron project initiated with VueCLI and a litle nodejs socket.io server, here's the server's file :
const http = require('http');
const express = require('express');
const socketio = require('socket.io');
const {
userJoin,
getCurrentUser,
userLeave,
getRoomUsers,
users
} = require('./utils/users');
const app = express();
const server = http.createServer(app);
const io = socketio(server);
// Set static folder
app.use(express.static(path.join(__dirname, 'public')));
// Run when client connects
io.on('connection', socket => {
console.log(`Connected tp ${socket.id}`)
app.get('/send-file', (req, res, next) => {
res.send('Sent')
})
socket.on('joinRoom', (args)=>{
console.log('joinroom')
})
// Runs when client disconnects
socket.on('disconnect', () => {
const user = userLeave(socket.id);
});
});
const PORT = process.env.PORT || 7575;
server.listen(PORT, () => console.log(`Server running on port ${PORT}`));
And here's my preload.js file :
const io = require('socket.io-client');
window.socket = io('http://localhost:7575');
window.socket.on('welcome', () => {
console.log('on welcome : welcome received renderer'); // displayed
window.socket.emit('test')
});
window.socket.on('error', (e) => {
console.log(e); // displayed ?
});
window.socket.on('ok', () => {
console.log("OK received renderer"); // displayed
});
window.socket.on('connect', () => {
console.log("connected renderer"); // displayed
window.socket.emit('test');
});
And here's my createWindow function:
async function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 700,
height: 600,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
enableRemoteModule: true,
preload: path.join(__dirname, 'preload.js')
}
})
win.setMenu(null)
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://./index.html')
}
}
The connection is made between the client and the server, because the console.log(Connected tp ${socket.id}) show a different socket ID everytime, but on my compenent, when I call the emit function nothing happens : window.socket.emit('joinRoom', {email:this.email, apikey:this.apikey})
And I can't event receive message on the client side, I've tested the server and everything works fine on a normale browser, but on my electron application can't emit or receive messages.
Is this related to my electron application?
Here's how I did it -
Server side:
const express = require('express')
const app = express()
// middlewares
app.use(express.static('public'))
// routes
app.get('/', (req, res) => {
res.render('index')
})
server = app.listen(7575, () => {
console.log("Server started");
})
//socket.io instantiation
const io = require("socket.io")(server)
//listen on every connection
io.on('connection', (socket) => {
console.log('New user connected');
//listen on "test"
socket.on('test', (data) => {
var username = data.username;
})
})
Client side:
socket = io.connect('http://localhost:7575')
socket.emit('test', {username: 'username'})
I am building an API that uses socket connection to interact with a server backend built in C#. This is what I have so far
const request = require('request');
const express = require('express');
const app = express();
var server = require('http').createServer(app);
var cors = require("cors");
app.use(cors());
const net = require('net');
const client = new net.Socket();
const stringToJson=require('./stringToJson')
const port = process.env.PORT;
const host = process.env.HOST;
client.keepAlive=true
client.on('close', function() {
console.log('Connection closed');
});
app.get('/getScores',function (req,res) {
let dataSend=''
client.on('data', function (data) {
console.log('Server Says : ' + data);
if(data!='ANALYSIS-ERROR'){
dataSend=stringToJson.stringToJson(data)
}
else{
dataSend=stringToJson.stringToJson('0:0.0:0.0:0.0:0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0')
}
client.destroy()
return res.send(dataSend)
});
client.connect(port, host, function () {
client.write(`GENERAL-ANALYSIS|${req.query.id}|${req.query.website}|`)
return
});
return
})
app.get('/getPlace',function (req,res) {
console.log(req.query)
request(
{ url: `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${req.query.name}+in+${req.query.city}&key=${process.env.API_KEY}` },
(error, response, body) => {
if (error || response.statusCode !== 200) {
return res.status(500).json({ type: 'error', message: error.message });
}
return res.json(JSON.parse(body));
}
)
})
//TODO ADD 404 500 PAGES
app.use((req, res, next) => {
res.status(404).send("Sorry can't find that!");
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
server.listen(9000, () => {
console.log(`App running at http://localhost:9000`);
});
Basically it creates a connection with the server and listens for some data to be sent back. Then processes the string and sends it to the React frontend. The api calls are made by the frontend using axios
It works but if you refresh the page it throws this error Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
How do I fix this?
Try setting the headers as found in the documentation request.setHeader(name, value)
request.setHeader('Content-Type', 'application/json');