How to keep socket.io client in frontend code - javascript

I am just learning webdev and want to try to make a multiplayer game using Express and socket.io
I can make a server with socket.io in it which listens. That part works fine.
However when I try to connect a client, this only works if I let the HTML file with the following in it be served by the server like follows:
Server code:
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)
const port = 3000
io.on('connection', (sock) => {
console.log('client connected')
})
// This seems to be necessary, but I don't want it to be!!!
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html')
})
server.listen(port, () => {
console.log(`Server listening on port ${port}`)
})
This index.html has the following at the bottom:
<script src="/socket.io/socket.io.js"></script>
<script>const socket = io()</script>
However I want to keep all my frontend code seperate from the server. I made a seperate repository for the frontend and backend. I want the frontend to contain all the UI logic and use only data calls (AJAX) to get Json data from the server. So I want to put this index.html file in my frontend code only.
Yet if I do this the connection doesn't work.
I can start the server fine.
I open index.html from WebStorm which also creates a server for this which I configured to also listen to port 3000
Yet it cannot find /socket.io/socket.io.js and I get the following error in the console.
It also doesn't work if WebStorm runs on a different port.
The resource from “http://localhost:3000/socket.io/socket.io.js” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).
How can I keep this html in my client repo only and still work with socket.io, or is this not possible?

You can't have multiple servers listening on the same port. Run the servers on different ports and either:
Have a reverse proxy forwarding requests to your Socket.io server (which needs special handling) and your front end server or
Put an absolute URL in the script src and configure CORS.

Related

Failed to load resource: the server responded with a status of 404 (Not Found) Node.js socket.io

I'm trying to create a server using Node.js and socket.io and it starts perfectly. However, when I'm trying to visit the site of my server through the browser, he writes "Cannot Get /" and in the console gives an error "Failed to Load Resource: The Server Respondd with A Status of 404 (Not Found)". For two days I'm trying to understand where the problem and I will be very grateful to your help. Here is my server code:
const express = require("express");
var http = require("http");
const app = express();
const port = process.env.PORT || 5000;
var server = http.createServer(app);
var io = require("socket.io").listen(server);
//middlewre
app.use(express.json());
io.on("connection", (socket) => {
console.log("connected");
console.log(socket.id, "has joined");
socket.on("/test", (msg) => {
console.log(msg);
})
});
server.listen(port, "0.0.0.0", () => {
console.log("server started");
});
Your server is currently not set up to handle any other http traffic than Websocket connection upgrade requests, which you can not make by entering a url in your browser. Also, the browser is not equipped to negotiate this connection upgrade or to keep the Websocket connection working once established. For this you need some javascript code to run on the client side.
The socket.io library provides everything you need, look at a minimally working example at the link provided below. You should basically just set up your server to serve an html document which provides a context from which the whole websocket connection upgrade can be managed - and the connection maintained - by the socket.io library.
https://socket.io/docs/v2#Minimal-working-example

Express server routes not being hit. Browser Error 'No Data Received ERR_EMPTY_RESPONSE'

I'm having an issue with my express server with an email service I was attempting to set up. After troubleshooting I decided to boil it down and attempt see if the issue would replicate with a simple 'hello world' example, which it did. No routes will be work correctly each request, whether done by a js frontend, postman, or just in a chrome browser will work. Each request will just 'spin' until it returns a 'No Data Received ERR_EMPTY_RESPONSE' error.
I've tried reinstalling the express dependency, reinstalling node itself, different browsers. The code is attached, any help would be appreciated.
const express = require('express');
const cors = require('cors');
const app = express();
let port = 3000;
app.use(cors);
app.get('/testroute', (req, res) => {
console.log('route hit');
res.send('test success');
});
app.listen(port, () => {
console.log('server started on port: ' + port);
});
Change this:
app.use(cors);
to this:
app.use(cors());
Your server was hanging because you were passing cors as middleware. But, cors by itself is not middleware. When Express called it, it never sent a response or called next() to continue routing, so therefore the client was just left hanging forever waiting for a response. Instead, the cors library is designed to that you call it as in cors() to get back a middleware function that you then pass to Express.
This is fully documented in the cors library documentation.

Sending data from client javascript file to server javascript file (node.js or other) and getting the response back

TL;DR:
How can I send data from client-side javascript to server-side javascript file (node.js or whatever), receive it there (and do some stuff with it), then send it back to client-side javascript file for further usage?
Full description of the issue
There is an HTML page with a form, from which myjavascript.js collect user input and process it on client side (using FormData). Then myjavascript.js sends the processed input to myphp.php (server-side) this way:
myjavascript.js:
ajax = new XMLHttpRequest();
ajax.open("POST", "../../myphp.php",false);
ajax.send(formdata);
return ajax.responseText;
The data (formdata) is then received by myphp.php, undergoes some further processing, and then is sent back to the myjavascript.js:..
myphp.php:
$fieldOne = $_POST["fieldOne"];
$fieldTwo = $_POST["fieldTwo"];
...
($fieldOne, $fieldTwo etc. are processed, and the result is assigned to $results)
...
echo json_encode($results);
exit();
... where it is returned by return ajax.responseText; (as in myjavascript.js code above). And then this data is displayed on the HTML page etc.
The question
I used to do this way before. Now I would like to use server-side javascript (say, myserver.js) instead of myphp.php. I have the code for processing the data in myserver.js, I just do not understand how to receive the data from myjavascript.js and send the response back. Is it possible, and if yes, how the code for it should look like? Generally, I do not quite understand how the mechanism of receiving POST data in server-side javascript (and sending the response back) differs from the PHP one. Thank you for any suggestions and comments.
In PHP, the web server portion is typically implemented by some other framework, and your PHP scripts are called by that framework. For example, an Apache module may call your blah.php script incoming web request is for /blah.php. This means PHP developers often think in terms of the browser calling a PHP file, but it's actually more complicated than that behind the scenes.
A typical Node.js setup, in contrast, is that the JavaScript code itself implements the web server listener. You run node with your server JS script, and that script starts the server. The built-in http module, for example, lets you implement an low-level HTTP listener through createServer:
const { createServer } = require('http');
const { once } = require('events');
const server = createServer(async (req, res) => {
const chunks = [];
req.on('data', chunk => chunks.push(chunk));
await once(req, 'end');
const body = JSON.parse(chunks.join(''));
// Do stuff with the body
res.statusCode = 200;
res.end('Success!');
});
server.listen(8080);
console.log('Server is listening at http://0.0.0.0:8080/');
So basically, stop thinking in terms of a client-side JavaScript file sending things to a server-side JavaScript file and think in terms of your browser sending an HTTP request to your HTTP server.
I'd recommend you use a framework instead like express or koa to build your server since it lets you more easily configure route-specific handling for requests, and they have the ability to use pre-built "middlewares" to do the common stuff like JSON body parsing and much more.
You need to use node js and express js so that you can reach your goal easily.
Run the following commands after installed node js:
$ npm install express --save
$ npm install body-parser --save
myserver.js
const express = require('express')
const app = express()
const port = 3000
const bodyParser = require('body-parser')
app.use( bodyParser.json() )
app.use(bodyParser.urlencoded({
extended: true
}))
app.get('/', function (req, res) {
console.log(req.body.fieldOne)
console.log(req.body.fieldTwo)
res.send('Hello World!')
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
And then, run your server with the bellow command:
$ node myserver.js

is it possible to provide restful service from react?

i'm working on a web project that should provide restful post service with react framework.
there are a lot of consuming rest service example on internet.
however, i want to provide restful service.
I tried the following,
1- provide service from react framework. i see it is not possible.
2- provide service from express and binding it with react via proxy
https://www.youtube.com/watch?v=v0t42xBIYIs
for this example, get method works but post method does not.
my express server like below.
const express = require('express');
const app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/api/customers', (req, res) => {
res.json(req.body);
});
const port = 5000;
app.listen(port, () => `Server running on port ${port}`);
after that, , use proxy and react code like this
componentDidMount()
{
fetch('/api/customers')
.then(res => res.json())
.then(customers => this.setState({customers}, () => console.log('Customers fetched...', customers)));
at that point i get the below error
customers.js:18 GET http://localhost:3000/api/vehicles 500 (Internal Server Error)
thank you for all advice.
i'm searching for best practice.
The result of a React application build are script bundles and html files (also can include source maps for debugging) commonly referred to as build artifacts.
The best practice is simple:
When Express is involved the React app should download the build artifacts and API responses from Express (commonly called backend in this scenario).
What happens when this is not followed:
1. React frontend server (typically webpack-dev-server) is used in production. This is not a good idea, webpack-dev-serveris meant to be used in development only.
2. Browser detects that JS code from the bundles downloaded from one server (frontend) attempts to call another server (backend) and triggers a security violation which is meant to improve security. People then use CORS HTTP headers (sent by backend) to make the backend tell browsers: "Don't worry about security and don't trigger security violations, I (the backend) has been hardened to such an extent that I don't care that some code downloaded not from me tries to access me". The browser complies and this results in security needlessly watered down.
When to proxy:
In development only. The webpack-dev-server is excellent for development with its support for Live Reloading, HMR etc. To keep those advantages the backend (Express) can and should serve as a reverse proxy for the frontend. E.g. when Express receives a request for a build artifact, it should download it from the frontend first and then use it to send the response back. This ensures CORS issues do not arise.
Two issues stand out
Post vs Get
You're serving your api from a post endpoint. Change it to get.
app.get('/api/customers', (req, res) => {res.json(vehicleList);});
fetch
In the UI, it shows you are fetching from localhost:3000 when you should be fetching from localhost:5000. I assume your proxy is rerouting 3000 -> 5000 so hopefully this isn't an issue. I would however doublecheck and try hitting the localhost:3000/api/customers url (copy and paste that into the url bar) and see if you see your json.
Also
It is certainly possible to have express serve the static react bundle from a the same base url as your api.
e.g.
app.use('/', express.static('public'));
app.post('/api/customers', (req, res) => {
res.json(vehicleList);
});
Actually, I think you didn't focus that both are running on two different ports
like your server is running on Port:5000 and react project port:3000 so just add
"proxy":http://localhost:5000
//server.js (node file)***
app.get('/api/customers', (req, res) => {
const customers = [
{id: 1, Name: 'Rohan', email: 'r#gmail.com'},
{id: 2, Name: 'Rohan', email: 'r#gmail.com'}
];
res.json(customers);
});
const port = 5000;
app.listen(port, () => `Server running on port ${port}`)
// React Script***
class Customers extends Component {
constructor() {
super();
this.state = {
customers: []
};
}
componentDidMount() {
fetch('/api/customers')
.then(res => res.json())
.then(customers => this.setState({customers}, () => console.log('Customers fetched...', customers)));
}
i think there is no method for pushing data from server to client in a convensional way.
there is a good subject to push data from server to client. you may want to see that.
WebSocket vs ServerSentEvents

Why heroku can't run WebSocket server without HTTP server?

I have a WebSocket app on heroku. I tried uploading my WebSocket app without routing http server but it doesn't work. What does mean server routing? And why can't heroku run a WebSocket server without an http server?
And why does it takes express object 'server' as argument in SocketServer
Here's my code of Websocket server.
const express = require('express');
const SocketServer = require('ws').Server;
const path = require('path');
const PORT = process.env.PORT || 3000;
const INDEX = path.join(__dirname, 'index.html');
const server = express()
.use((req, res) => res.sendFile(INDEX) )
.listen(PORT, () => console.log(`Listening on ${ PORT }`));
const wss = new SocketServer({ server });
wss.on("connection",function(ws){
ws.on("message",function(message){
if(message==='exit'){
ws.close();
}else{
wss.clients.forEach(function(client){
client.send(message);
});
console.log(message);
}
});
ws.send("welcome..");
});
There are too many questions in one. I hope my answers will address all of them.
First of all, the websocket protocol is an extension of http, it is not something different. Therefore, a websocket server is necessarily an http server, even though with extended capabilities.
Also, with socket.io, the websockets and http run on the same port. Therefore you have to open the port for http to have your websockets work.
Let's have a look at this line :
const wss = new SocketServer({ server });
It has a syntax error, it must be new SocketServer(server). Also, about the variable name, I would recommend not to use wss for a websocket over http, since wss stands for secure websockets and is related to websockets like http to https.
About routing in heroku: in heroku, you have to define which port your application is using. This can be compared to the firewall on your local machine : if you want to access it from outside, you have to open the port. On heroku, technically it is different to a firewall, but in this point it is similar.

Categories

Resources