Im trying to send 10 GB data from a node client to a node http server. It works fine until i reach about 5 GB. Protocol is http.
It works fine until i reach about 5 GB. Error I get on server side is [ERR_STREAM_PREMATURE_CLOSE] and on client side RequestError: read ECONNRESET.
example server:
const http = require('http')
const fs = require('fs')
const util = require('util')
const stream = require('stream')
const pipeline = util.promisify(stream.pipeline)
const host = 'localhost'
const port = 4000
const server = http.createServer(async (req, res) => {
try {
const writeStream = fs.createWriteStream('file', { encoding: 'binary' })
await pipeline(req, writeStream)
} catch (e) {
console.log(e)
}
})
server.listen(port, host, () => {
console.log(`Server is running on http://${host}:${port}`)
})
example client
const got = require('got')
async function upload () {
await pipeline(fs.createReadStream(filename), got.stream.post('http://localhost:4000/upload'))
}
I have tried with different servers (raw http and express) and clients (raw node, request, node fetch). Ive also tried multipart with busboy. Same problem.
Im trying this running node v14.4.0 on a Mac.
I tried transferring a 10 gb file on my computer and it worked for me.
Server example:
const http = require('http');
const fs = require('fs');
const PORT = 8333;
const server = http.createServer((req, res) => {
const writeStream = fs.createWriteStream('./result.txt');
req.pipe(writeStream);
req.on('end', () => {
console.log('The file was successfully written.');
res.end('OK');
});
});
server.listen(PORT, () => {
console.log(`Server has been started on port ${server.address().port}`);
});
Client example
const http = require('http');
const fs = require('fs');
function upload() {
const readStream = fs.createReadStream('./test.txt');
const request = http.request('http://localhost:8333', { method: 'POST' }, (res) => console.log(`STATUS: ${res.statusCode}`));
readStream.pipe(request);
readStream.on('end', () => request.end());
}
upload();
I am not saying that this code is very correct, but you can try it, since it worked for me.
I ran this example on Node.js v12.4.1 and Windows 10.
Related
I'm running two apps that sends real-time messages to each other using websocket and also generate a random link using express.js, now i hosted the server with both react apps to my vps host and want to make the websocket connection secure (wss://) but i realize i'll have to get the express server on the same port too, so the ssl/tsl works for both - so how do i do that?
Here is my full code, all on the same file:
const webSocketServerPort = 8000;
const webSocketServer = require('websocket').server;
const http = require('http');
const server = http.createServer(); server.listen(webSocketServerPort); console.log('Listening on port 8000');
const wsServer = new webSocketServer({ httpServer: server })
//GEERTOOOO
const express = require('express'); const cors = require('cors'); const fs = require('fs'); const app = express();
app.use(cors({ origin: '*' }));
app.get('/', (req, res) => { // Generate a random 6-character string const linkId = Math.random().toString(36).substr(2, 6);
// Save the link in the lex.json file fs.readFile('lex.json', (err, data) => { if (err) { console.error(err); res.status(500).send('Error generating link'); return; }
const links = JSON.parse(data);
links[linkId] = {
destination: 'http://localhost:4000/',
expires: Date.now() + 1000 * 60 * 5 // expires in 5 minutes
};
fs.writeFile('lex.json', JSON.stringify(links), (err) => {
if (err) {
console.error(err);
res.status(500).send('Error generating link');
return;
}
// Send the link back to the client
res.send(`http://localhost:3000/${linkId}`);
});
}); });
app.get('/:linkId', (req, res) => {
fs.readFile('lex.json', (err, data) => {
if (err) { console.error(err); res.status(500).send('Error retrieving link');
return;
}
const links = JSON.parse(data);
const link = links[req.params.linkId];
if (!link) {
res.status(404).send('Link not found');
return;
}
// Check if the link has expired
if (link.expires < Date.now()) {
res.status(410).send('Link has expired');
return;
}
// Redirect to the destination
res.redirect(link.destination);
}); });
app.listen(3000, () => { console.log('Server listening on port 3000'); });
//GEERTOOOO
const clients = {};
const getUniqueID = () => { const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
return s4() + s4() + '-' + s4(); }
wsServer.on('request', (request) => { var userID = getUniqueID();
const connection = request.accept(null, request.origin); clients[userID] = connection;
connection.on('message', (message) => {
if (message.type === 'utf8') {
for(var key in clients) {
if (clients[key] !== clients[userID]) {
clients[key].sendUTF(message.utf8Data);
console.log(`Sent Message to: ${clients[key]}`);
}
}
}
}) })
Note: the express server is on port 3000 and the websocket server runs on port 8000.
I,ve tried just changing the port to same thing but i get an error when trying to use the websocket server for messages.
THE PURPOSE OF ALL THIS IS JUST TO MAKE THE WEBSOCKET CONNECTION AND EXPRESS CONNECCTION SECURE SO MY APPS (with letsencrypt ssl) can connect to the servers
It is not possible to create two separate server instances, both listening on the same port. But, specifically for a webSocket, you can share one server instance between Express and the webSocket server code. This is possible because a webSocket connection always starts with an http request (thus it can be listened for using your Express http server. And, because these http requests that initiate a webSocket all contain identifying headers they can be separated out from the regular http requests for Express by looking at the headers. The webSocket server code already knows how to do that for you.
To do that, first capture the Express server instance:
const server = app.listen(3000, () => { console.log('Server listening on port 3000'); });
Then, use that server instance when you create your webSocket server.
const wsServer = new webSocketServer({ httpServer: server });
Then, remove this code because you don't want to create yet another http server instance for the webSocket server:
const server = http.createServer();
server.listen(webSocketServerPort);
console.log('Listening on port 8000');
I am trying to fetch data from my local server and here is my server and how I handled GET requests:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.listen(port, () => {
console.log(`app running on port: ${port}...`);
});
const responseToClient = (req, res) => {
res.status(200).json({
status: 'success',
body: 'Hello from the server!',
});
};
app.get('/api', responseToClient);
When I run my server and send a GET request to this address: 127.0.0.1:3000/api with Postman, it works perfectly.
The thing is I created a html page along with a js file and want to fetch data from my local server by it. Here is my fetch request on my js file:
const url = '/api';
const fetchData = async () => {
try {
const response = await fetch(url);
const body = await response.json();
alert(body);
} catch (error) {
alert(error);
}
};
fetchData();
I run my html file with live-server (extension) which runs on port 5500 by default , so the address my fetch request goes to will be 127.0.0.1:5500/api (instead of 127.0.0.1:3000/api), so it does not exists and I get an error message.
I tried to change the port of my server and set it to 5500 (the same as live-server) but it did not work.
How can I run my local server and send requests to it with live-server and my html file?
Solved by using:
const url = 'http://localhost:3000/api';
instead of the ip address and installing cors middle ware.
If you do not want to have the HTML and JS files static-ed onto your Express server, then try this:
const url = '/api'; // bad
const url = '127.0.0.1:3000/api'; // better
I'm writing a server and a client with Node.js, the server uses express and the client uses axios.
I'm trying to send an image file from the client to the server. I found somewhere here this bit of code for the client:
let file = fs.createReadStream(file_path);
let form_data = new FormData();
form_data.append("picture", file);
let post_config = {
method: "post",
url: SERVER_PICTURE_URL,
headers: {"Content-Type": "multipart/form-data"},
data: form_data
}
axios(post_config).then(_ => {console.log("sent");} );
But I can't figure out what's supposed to be on the server side. I've tried the most obvious solution, writing response.data or response.form to a file, but both are undefined.
Is there some parser I'm supposed to use? And if so, how?
I'm not sure about the client that you wrote, but in express, you need to use express-fileupload package for getting the picture from req.files
const express = require('express');
const fileupload = require("express-fileupload");
const app = express();
const port = 3000;
app.use(fileupload());
app.post('/picture', (req, res) => {
const files=req.files;
res.send(files)
})
app.listen(port, () => {
console.log(`app listening at http://localhost:${port}`)
})
I am looking for a way to send the url to the nodejs server and respond the user with the mp3 file download.
I searched some examples, and read about requests and responses, but I am not sure what the problem really is.
This is the Javascript for the HTML:
var downloadBtn = document.querySelector('.download_button');
var URLinput = document.querySelector('#myUrl');
downloadBtn.addEventListener('click', () => {
console.log(`URL: ${URLinput.value}`);
sendURL(URLinput.value);
});
function sendURL(URL) {
window.location.href = `http://localhost:4000/download?URL=${URL}`;
}
This is the Javascript for the Nodejs server:
const express = require('express');
const cors = require('cors');
const ytdl = require('ytdl-core');
const app = express();
const ffmpeg = require('fluent-ffmpeg')
app.use(cors());
app.listen(4000, () => {
console.log('Server Works !!! At port 4000');
});
app.get('/download', (req,res) => {
var URL = req.query.URL;
res.header('Content-Disposition', 'attachment; filename="file.mp3"');
let stream = ytdl(URL, {
quality: 'highestaudio',
}); //HERE THE STREAM FILE IS SELECTED TO BE CONVERTED TO MP3
ffmpeg(stream)
.audioBitrate(128)
.pipe(res); // HERE IS CONVERTED AND WHERE I WANT IT TO SEND IT AS A DOWNLOAD TO THE USER.
});
I expected it to stream download the file but instead it gets me to the nodejs server page to /download/url_to_vid
I try to create a http server that will download the HTML at https://google.com
And serve it (at localhost:3000). Kind of a proxy.
With this code:
const express = require('express')
const https = require('https')
const app = express()
app.get('/', function (req, mainRes) {
https.get('https://www.google.fr', (res) => {
res.on('data', (d) => {
mainRes.send(d)
})
})
})
app.listen(3000)
The html from google.com seems to be downloaded, but the server crashes with this error :
Error: Can't set headers after they are sent.
I Understand it's related to the 2 wrapped requests but I don't know how to fix it.
In your code the argument res is a stream (see the docs for https.get).
Currently you are attempting to send the complete response each time a chunk is received through that stream. Hence you are getting the error Can't set headers after they are sent., because the second time mainRes.send() is called you are trying to send the whole response again. (See the docs for express' res.send.)
You want to pipe res through the express response object, as this is also a stream:
const express = require('express')
const https = require('https')
const app = express()
app.get('/', function (req, mainRes) {
https.get('https://www.google.fr', (res) => {
mainRes.pipe(res)
})
})
app.listen(3000)
I am not 100% sure in your case but I would suggest you to add a debugger statement and step through it.
#sdgluck && #kwesi1337 helped me find a solution, I need to concat all chunks from the data event :
const express = require('express')
const https = require('https')
const app = express()
let data = ''
app.get('/', function (req, mainRes) {
https.get('https://www.google.fr', (res) => {
res.on('data', (chunk) => {
data += chunk;
})
res.on('end', () => {
mainRes.end(data);
});
})
})
app.listen(3000)