Unable to connect to socket - Vanilla JS to node.js - javascript

I am trying to work with socket.io, however I am unable to establish a connection between my client (Vanilla HTML/JS) and my server (node.js).
Server code:
const express = require('express');
var cors = require('cors');
const app = express();
app.use(cors())
app.use(express.json());
app.use(express.urlencoded());
var server = app.listen(3001, () => console.log('Listening on port 3001!'));
const io = require('socket.io')(server)
io.on('connection', (socket) => {
console.log("A user connected");
socket.on('disconnect', () => {
console.log("user disconnected")
})
})
I also have several endpoints and functions that are exposed in the same file, though they didn't seem relevant (as far as I know), so I didn't include them here, but can if needed.
HTML:
<head>
<script src="https://cdn.jsdelivr.net/npm/socket.io-client#2/dist/socket.io.js"></script>
<script src="../scripts/index.js"></script>
</head>
index.js:
window.onload = () => {
var socket = io("http://localhost:3001")
socket.on('connect', () => {
console.log("Connected")
console.log(socket.connected)
})
socket.on('test', () => {
console.log("In test socket on")
})
}
I don't seem to be getting any errors thrown in the console or anything, and am not sure where the issue is coming from.

I had a similar issue. I solved it by specifying the origin on cors. Don't just allow all origins through the cors. Instead of app.use(cors()) , use app.use(cors({ credentials: true, origin: 'http://localhost:8080', optionsSuccessStatus: 200 })) or whatever your front end server port is. socket.io also has an option to set origin when initializing. Try this. const io = require('socket.io')(server, { origins: '*:*'});

So as it turns out, the configuration I had for both the client and the server were ok, however it seems as though the issue was with the version of socket.io that I was using. The version I was using was 3.0.3, however when rolling it back to 1.7.4, the setup had worked and I was able to successfully connect to the socket. This isn't an ideal situation by any means, I believe with version 3, the configuration has to be modified. As a quick, temporary fix, this may help, though of course this is by no means an ideal, production-level solution.

I had the same problem. And all i did was let Express know where my static files were.
With:
app.use(express.static(__dirname + '/public')) //Make sure you set here you actual folder
(in my case it was "/public")
I'm using the CDN provided by Socket.io docs:
<script src="https://cdn.socket.io/3.1.3/socket.io.min.js" integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>.
Also i'm declaring the CDN at the end of the file before the closing body tag before my actual JS script containing the implementation.
Also i'm using res.sendFile(*insert here template path*) for example res.sendFile(__dirname + '/public/templates/index.html').

Related

Do you usually need install/declare anything in your frontend for CORS to be allowed?

I am currently working on a react/express project and I get this error:
Error: A cross-origin error was thrown. React doesn't have access to the actual error object in development. See https://reactjs.org/link/crossorigin-error for more information.
I have enabled CORS in my server.js like this:
const express = require("express"),
app = express(),
port = process.env.PORT || 5000,
cors = require("cors");
{Sequelize, Model, QueryTypes } = require('sequelize');
app.use(cors());
app.use(express.json());
I also have no issues with displaying the original data in console.
This is basically what causes it to break.
allDetails=JSON.parse(details);
Getting and sending the data:
async function connect() {
var detailsArray=[]
try {
await sequelize.authenticate();
console.log('Connection has been established successfully.');
} catch (err) {
console.error('Unable to connect to the database:', error);
}
info = await sequelize.query('select * from Information', { type: QueryTypes.SELECT });
let details = JSON.stringify(info);
detailsArray=JSON.parse(details);
return details;
}
app.get("/list", async (req, res) => {
const result = await connect();
res.json(result);
});
I also made sure to npm install for both my client and server side a few times to double check and triple check that it was installed.
Am I missing something?Or do I need anything in my client side to solve this issue. This is very confusing and whatever solution I tried for my CORS issue did not work either. Powershell is also not giving any errors regarding me trying to parse my data. I am not very familiar with cross origin related errors so an explanation would be very much appreciated.
When this error happens:
The error happens when I try to JSON.parse() the data received but when using console.log to display the raw data it is fine. So before that nothing breaks.
If I understand correctly, you are running both front-end and server on your local machine during development and getting CORS error, if so, since you are using express and have already required the CORS module, you still need to use it as a middleware to your express app - Express - Using middleware:
const express = require("express");
const app = express(),
const port = process.env.PORT || 5000,
const cors = require("cors");
app.use(cors());
app.listen(5000);

How should I use proxy in a web app made with node.js and vanilla javascript?

I have a web app made in node.js and vanilla javascript. I wanna replace "http://localhost:4000/api/word" with "api/word" in the fetch api so that it works when the app's deployed on Heroku. I solved the issue by adding "proxy" : "http://localhost:4000" in package.json file when I used React for other apps but I don't know how to deal with the issue when I'm not using React.
server.js
const express = require("express");
const app = express();
const cors = require("cors");
const fs = require("fs");
const port = process.env.PORT || 4000;
app.use(express.json());
app.use(cors());
app.get("http://localhost:4000/api/word", function (req, res) {
fs.readFile("./wordlist.txt", (err, data) => {
if (err) throw err;
let wordList = data.toString().split("\n");
res.send(wordList);
});
});
main.js
function getWord() {
fetch("/api/word")
.then((res) => res.json())
.then((res) => {
...do something...
})
.catch((err) => console.log(err));
}
I tried the React way but it sends the get request to localhost:5500 which is the client side port.
Since your client and server are listening on different ports, I'm assuming your server isn't serving the client and that it has its own server. If the client doesn't need its own separate server, you can serve it from your express app by putting it in a directory and using express.static. Assuming you put the frontend code in a directory called public next to your server code, that would look like this:
app.use(express.json());
app.use(cors());
app.use(express.static(path.resolve(__dirname, 'public')));
If you do need to have a separate server for the client, there are modules just for this problem. http-proxy is a very popular one. I provided examples of how to use it here that could be easily adapted for any Node server, but there are many more in the docs.
Also just a sidenote, app.get("http://localhost:4000/api/word", function (req, res) should be app.get('/api/word' ...: your routes shouldn't define the scheme, host, and port.

How can I connect to an established server (NOT localhost) with node.js & socket.io?

I am very new to web servers / node.js / socket.io and I'm trying to make a very simple website just to learn how to connect 2 people. All of the tutorials I've found teach you how to run your app on localhost, but I want to run it on a server so everyone can access it.
I found this hosting website - Zeit-Now - and managed to put my website online. My website works just fine on localhost, but I can't get it to work when i put it online. I think the problem is in these 2 lines in my code, where the '???' are.
index.html:
<!DOCTYPE html>
<html>
<head>
<title>A2</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
</head>
<body>
<input id="sendMsg" type="text" placeholder="TYPE TO SEND">
<input id="receiveMsg" type="text" placeholder="RECEIVE HERE">
<button id="sendBtn">Send</button>
<script>
var socket = io.connect('https://web-socket-2.quaei.now.sh/');
var sendMsg = document.getElementById('sendMsg');
var receiveMsg = document.getElementById('receiveMsg');
var sendBtn = document.getElementById('sendBtn');
// Emit events
sendBtn.addEventListener('click', () => {
socket.emit('chat', {
message: sendMsg.value
});
});
// Listen for events
socket.on('chat', data => {
receiveMsg.value = data.message;
});
</script>
</body>
</html>
index.js:
const express = require('express');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
app.use(express.static('public'));
io.on('connection', socket => {
console.log('Connection! ->', socket.id);
socket.on('chat', data => {
io.sockets.emit('chat', data);
});
});
I've also tried:
var socket = io.connect(https://web-socket-2.quaei.now.sh/);
and
var server = app.listen(80, https://web-socket-2.quaei.now.sh/);
I expect my website to read what is written in the first input field and output it in the second one when clicked send (which works fine on localhost), but it doesn't work when I put it online with Zeit-Now.
Edit:
now.json:
{
"version": 2,
"name": "web-socket-2",
"builds": [{
"src": "public/**/*",
"use": "#now/static"
},
{
"src": "*.js",
"use": "#now/node"
}
],
"routes": [{
"src": "/",
"dest": "public/index.html"
}]
}
I have a #websocket-2 folder with now.json, index.js and public folder. In public folder I have index.html.
How can I make it work on this website: https://web-socket-2.quaei.now.sh/ ?
I guess the problem you face at the moment is that you want to run the server directly on the website. But it's need to be run by node like this:
node index.js.
Therefore you need access to the server like some ssh access and then start it there with the command named above. Based on the logs, I can say that the client can't find the server.
You also need to make sure that it resolves to the right path.
Start it with app.listen(80) and then try to connect to
https://web-socket-2.quaei.now.sh:80
try this
const app = express();
const server = http.createServer(app);
const io = socketio(server);
server.listen(80, '0.0.0.0');
Make sure your server has websockets enabled. (It does not actually need websockets, but it will use it if possible for better transport)
Reading about zeit.co I can see they dont support websockets, not sure if they support sucket either. I would recommend you hitting them up with email to confirm this if code below does not help you.
To run connection on client side, after you have installed socket.io-client or after you have included script in header, which you have.
You simply connect using io.connect('SERVER URL') which will return your socket connection instance. (no need to pass server if running on same server)
const socket = io.connect('http://youserver.com');
// You can listen to conenct and disconnect to track your connection
socket.on('connect', socket => {
console.log('Connected', socket.id);
});
Thats it on client side.
On server side, you need to pass server to your socket.io module
const io = require('socket.io')(server);
// You can listen to your socket connecting through connect and disconnect
io.on('connect', (socket) => {
console.log('socket connected', socket);
});
You can track your errors on client side using 'error' event, and make sure to check your console to see the logs about the connection.
In case you are using express server, and socket is raising 404 errors in console, make sure you initiate server using http instead of express.
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
// your socket and routes
server.listen(process.env.PORT || 3500, () => {
console.log(`Localhost working on ${process.env.PORT || 3500}`);
}

How can I make my localhost server available from external requests?

I'm running a simple nodejs server on my localhost on port :3434
const cors = require('cors');
const app = require('express')();
const bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
app.get('/ping/:anystring', (req, res) => {
console.log(req.params['anystring']);
res.send({
anystring: req.params['anystring']
})
});
app.listen(3434);
and I'd like to perform some ajax call from a website of mine.
I tried to configure the router port forwarding like so:
- name service: mylocalserver
- porta ragnge: 3434
- local ip: 192.168.1.19
- local port: 3434
- protocol: BOTH
but when I do
fetch(publicIP:3434/ping/hello).then(res => {
console.log(res);
})
I get error 404
Might anyone help me telling what I'm doing wrong?
You can't access your localhost server outside of your LAN unless you create a tunnel. I use ngrok.
There is an npm package for ngrok, but I couldn't get that one working, so I just manually start the server from terminal whenever I need to test an API.
Also you'll need http.
add this to your app.js:
const http = require('http');
const newPort = //your port here (needs to be a different port than the port your app is currently using)
const server = http.createServer(function(req, res) {
console.log(req); //code to handle requests to newPort
res.end('Hello World);
});
app.listen(newPort, function() {
console.log(`ngrok listening on ${newPort}`);
});
Now in terminal, after installing ngrok, use this ngrok http newPort where newPort = your port
You can view requests sent to your server by going to localhost:4040 (this might change depending on your system)
To send a request to your localhost, do this:
- name service: mylocalserver //not sure
- porta ragnge: ???
- local ip: //ngrok gives you a url in terminal when you start the server (I'm not sure if you can reference an IP)
- local port: newPort
- protocol: http //(ngrok gives you a different url for http and https)
You can use local tunnel
It maps your port on the localhost to a web url whithout the need to change your code

How to write a node express app that serves most local files, but reroutes some to another domain?

I'm working on a small webapp that normally is built with a relatively complex process and then deployed to WebLogic.
However, the portion I'm working on is using AngularJS, and is all HTML and Javascript. It normally makes ajax calls into another webapp on the same domain. To shorten my development cycle, I'd like to avoid a build process and just reload the browser page.
I think I can do this with "node express", but the details escape me. I've managed to define a very simple app that just serves local files, but now I have to figure out how to detect some of those paths as matching an expression, and reroute those requests to a request to an external domain.
So, if it gets a request for "/diag/stuff.html", "/foo/thing.html", or just "/index.html", it will send back the file matching the same path. However, if the path matches "/fooService/.*", then I have to send back the response from a GET to the same path, but on a different host and port.
This is my trivial app so far:
var express = require('express');
var app = express();
app.use("/", express.static(__dirname));
app.listen(8000);
Update:
I like the proxy idea, so I did a local install of "http-proxy" (I forgot and first did a global install) then changed the script to this:
var express = require('express');
var app = express();
var httpProxy = require('http-proxy');
var proxy = new httpProxy.RoutingProxy();
app.use("/", express.static(__dirname));
app.get('/FooService/*', function(req, res) {
"use strict";
return proxy.proxyRequest(req, res, {
host: "foohost.net",
port: 80
});
});
app.listen(8000);
This fails with:
<path>\server.js:4
var proxy = new httpProxy.RoutingProxy();
^
TypeError: undefined is not a function
at Object.<anonymous> (<path>\server.js:4:13)
What might be wrong here?
Update:
Would it be useful to see the contents of "console.log(httpProxy)" after that "require"?:
function ProxyServer(options) {
EE3.call(this);
this.web = this.proxyRequest = createRightProxy('web')(options);
this.ws = this.proxyWebsocketRequest = createRightProxy('ws')(options);
this.options = options;
this.webPasses = Object.keys(web).map(function(pass) {
return web[pass];
});
this.wsPasses = Object.keys(ws).map(function(pass) {
return ws[pass];
});
this.on('error', this.onError.bind(this));
}
Does that provide a clue for why "new httpProxy.RoutingProxy()" says it's undefined?
You can use http-proxy and forward requests to different host. To install http-proxy you need to run sudo npm install http-proxy. Code that will handle proxy will look like that:
httpProxy = require('http-proxy');
proxy = new httpProxy.RoutingProxy();
(...)
app.get('/fooService/*', function (request, response) {
"use strict";
return proxy.proxyRequest(request, response, {
host : externalHost,
port : 80
});
});
UPDATE
Above code is working for http-proxy ~0.10.x. Since then lot of things had changed in library. Below you can find example for new version (at time of writing ~1.0.2):
var httpProxy = require('http-proxy'),
proxy = httpProxy.createProxyServer({});
(...)
app.get('/fooService/*', function (request, response) {
"use strict";
return proxy.web(request, response, {
target: 'http://fooservice.com'
});
});
If redirects meet your need, then that's the easiest solution:
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(app.router);
app.get('/fooService/*', function(req, res){
res.redirect(302, 'http://otherdomain.com:2222' + req.path);
});
app.listen(8000);
Note that it's generally considered good practice to use a subdirectory for your static files (like public above). Otherwise you could view your app file itself and anything else you keep in your application root!

Categories