How to handle multiple requests to a file in node.js server - javascript

I'm trying to serve multiple audio files in the node.js server, but the server sometimes fails when multiple clients try to access. How can I remedy this?
express = require('express');
const http = require('http');
const path = require('path');
const fs = require('fs');
const app = express();
app.get('/', function (request, response) {
let fpath = base_dir + filenames[getIndex(filenames.length)];
let filestream = fs.createReadStream(fpath);
var d = new Date();
filestream.on('open', function() {
let stats = fs.statSync(fpath);
let fileSizeInBytes = stats["size"];
response.writeHead(200, {
"Accept-Ranges": "bytes",
'Content-Type': 'audio/mpeg',
'Content-Length': fileSizeInBytes});
filestream.pipe(response);
});
})
app.listen(3000, function () {
console.log('Audio file provider listening on port 3000');
})

You're using fs.statSync() which will block the thread also listening for incoming connections. Instead you should switch to the asynchronous version fs.stat().
app.get('/', (req, res) => {
let fpath = base_dir + filenames[getIndex(filenames.length)]
let d = new Date()
fs.stat(fpath, (err, stats) => {
// Handle Error when trying to get file stats
// Respond with 500 Internal Server Error
if (err) {
console.log(err)
return res.sendStatus(500)
}
let {size} = stats
res.status(200)
res.setHeader('Accept-Ranges', 'bytes')
res.setHeader('Content-Type', 'audio/mpeg')
res.setHeader('Content-Length', size)
fs.createReadStream(fpath).pipe(res)
})
})

You're already using express, no need to reinvent the wheel http://expressjs.com/en/4x/api.html#res.sendFile
app.get('/', function (request, response) {
let fpath = base_dir + filenames[getIndex(filenames.length)];
response.sendFile(fpath, function(err) {
//Handle err if any
});
})

Related

NodeJS: Server.on-listenerfunction doesn't exist when exporting?

I am using server.js to start the server and router.js to listen to the requests. When I try to access the server, nothing happens and I can't reach it, I assume so, because the server.on function doesn't execute. Everything works, when I put it just in the server.js tho, so the error seems to be in with the exports/imports, but I can't figure out what it is.
server.js:
const fs = require("fs");
const http = require("http");
const template = require("./template.js");
const port = 3000;
const server = http.createServer();
server.listen(port, () => {
console.log(`Server listening on localhost:${port}`);
})
module.exports = server;
router.js:
const server = require("./server.js");
const template = require("./template.js");
server.on("request", (req, res) => {
let url = req.url;
let method = req.method;
let html;
console.log("received req");
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
if(url.endsWith("/feedback") && method == "GET") {
html = template.createHtml("Liste der Feedbacks");
} else {
html = template.createHtml(`Methode: ${method}, URL: ${url}`);
}
res.end(html);
})
If you are looking to import the router.js and have the server object accessible in that file and execute the on method on it, one way to do it is by passing the server while requiring the router.js file as follows:
server.js:
const fs = require("fs");
const http = require("http");
const port = 3000;
const server = http.createServer();
const router = require("./router.js")( server );
server.listen(port, () => {
console.log(`Server listening on http://localhost:${port}`);
});
router.js:
const template = require("./template.js");
module.exports = function handleRequest( server ){
return server.on("request", (req, res) => {
let url = req.url;
let method = req.method;
let html;
console.log("received req");
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
if(url.endsWith("/feedback") && method == "GET") {
html = template.createHtml("Liste der Feedbacks");
} else {
html = template.createHtml(`Methode: ${method}, URL: ${url}`);
}
res.end(html);
})
}
Whatever pattern you try, make sure to avoid Circular dependencies.
Also, as a general recommendation, I would suggest that you try and avoid tight coupling in modules such as these whenever possible. Ideally, the router module should not be tightly coupled to the server module.

How to access next.js rendered HTML via custom server

I want a server side generated page in next.js to be served as a file. So I wanted to grab the rendered content inside a custom server.js file:
const express = require('express');
const next = require('next');
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({dev});
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.get('/', async (req, res) => {
const nextResponse = await app.renderToHTML(req, res, '/', req.query);
console.log('nextResponse', nextResponse);
console.log('res.body', res.body);
});
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});
Oddly enough every console.log returns null or undefined.
I thought that renderToHTML would just return the rendered HTML string. Is there any way to do this?
This one is a bit tricky but achievable.
The idea is to override res.end function in order to catch rendered HTML there. The tricky part is that Next.js gzips and streams response using the compression library that's overriding res.end somewhere in the middle of the handle function.
The compression library is initialized using the handleCompression function of the Next.js's Server object (which is accessible using the app.getServer()), so that function needs to get overridden too.
So it should be looking something like this:
const { parse } = require('url');
const next = require('next');
const express = require('express');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const port = process.env.PORT || 3000;
const handle = app.getRequestHandler();
app.prepare()
.then(() => {
const server = express();
server.get('*', async (req, res) => {
const parsedUrl = parse(req.url, true);
const nextServer = await app.getServer();
const _handleCompression = nodeServer.handleCompression.bind(nodeServer);
nextServer.handleCompression = (req, res) => {
_handleCompression(req, res);
const _resEnd = res.end.bind(res)
res.end = function (payload) {
console.log('Rendered HTML: ', payload);
return _resEnd(payload);
}
}
return handle(req, res, parsedUrl);
});
server.listen(port, err => {
if (err) throw err;
console.log('> Ready on http://localhost:' + port);
});
});
After you get rendered HTML you don't have to use the saved _resEnd function. Feel free to manipulate, serve as a file, or whatever you want with it.

Problem with redirecting user to a static HTML page

I am beginning to code in Javascript and Nodejs. I am checking if a post call has been made to recFile and accept the file sent. For all other http requests made I want to return a static HTML page. When I tried res.redirect it said 'res.redirect is not a function'
const bodyparser = require('body-parser');
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
const express =require('express');
const { response } = require('express');
const app = express();
http.createServer(function (req, res) {
if (req.url == '/recFile') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var newpath = './Uploads/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
})
});
} else {
// Need to send user here to a HTML page. But don't know how to do that.
// res.write is not viable as there is a lot of HTML lines of code.
return res.end();
}
}).listen(9000);
Try
response.writeHead(302, {
'Location': 'your/404/path.html'
//add other headers here...
});
response.end();
(Information from Nodejs - Redirect url, did you google it properly?)

JSON.parse() Returning Unexpected end of input

[`const express = require('express');
const app = express();
const https = require('https');
const url = "https://api.thevirustracker.com/free-api?countryTimeline=US";
app.get("/", (req ,res) => {
res.send("Server is Running")
https.get(url, (response) => {
response.on("data", (data) => {
const TimelineData = JSON.parse(data);
console.log(TimelineData);
})
})
})
app.listen(3000, ()=>console.log("Server is Running 0n 5000"));`]1
const express = require('express');
const app = express();
const https = require('https');
const url = "https://api.thevirustracker.com/free-api?countryTimeline=US";
app.get("/", (req ,res) => {
res.send("Server is Running")
https.get(url, (response) => {
response.on("data", (data) => {
const TimelineData = JSON.parse(data);
console.log(TimelineData);
})
})
})
app.listen(3000, ()=>console.log("Server is Running 0n 5000"));
To deliver large data in an effective manner API send data in chunk/stream format. and to receive each chunk it triggers the 'data' event and in your case, it might be possible that API sends data in chunk format. and it will not send you complete data in a single event.
Let's assume the complete response of your API is :
{ name: 'bella', age: 34, count: 40138 }
And API send it in 2 chunks :
Chunk1: { name: 'bella', age: 34, count: 4013
Chunk2: 8 }
In that case Json.Parse() on Chunk1 or Chunk2 will not work and threw an exception.
To deal with this problem you need to listen to the 'end' event and capture data from the'data' and parse it in the 'end' event.
Use the below code:
const express = require('express');
const app = express();
const https = require('https');
const url = "https://archive.org/advancedsearch.php?q=subject:google+sheets&output=json";
app.get("/", (req, res) => {
res.send("Server is Running")
https.get(url, (response) => {
var responseData = '';
response.on("data", (dataChunk) => {
responseData += dataChunk;
})
response.on('end', () => {
const TimelineData = JSON.parse(responseData);
console.log(TimelineData);
});
}).on('error', (e) => {
console.error(e);
});
})
app.listen(5000, () => console.log("Server is Running 0n 5000"));
The "data" event can be fired multiple times: https://nodejs.org/api/http.html#http_class_http_clientrequest
You have to listen for the "end" event and concat all chunks from the "data" event togehter for the full body response.
const express = require('express');
const app = express();
const https = require('https');
const url = "https://api.thevirustracker.com/free-api?countryTimeline=US";
app.get("/", (req, res) => {
res.send("Server is Running")
https.get(url, (response) => {
const chunks = [];
response.on("data", (data) => {
chunks.push(data);
})
response.on("end", () => {
let size = chunks.reduce((prev, cur) => {
return prev + cur.length;
}, 0);
let data = Buffer.concat(chunks, size).toString();
console.log(JSON.parse(data))
});
})
})
app.listen(3000, () => console.log("Server is Running 0n 5000"));
why are you using https?
replace https with http and run it again.
const express = require('express');
const app = express();
const http = require('http');
const url = "https://api.thevirustracker.com/free-api?countryTimeline=US";
app.get("/", (req ,res) => {
res.send("Server is Running")
http.get(url, (response) => {
response.on("data", (data) => {
const TimelineData = JSON.parse(data);
console.log(TimelineData);
})
})
})
const express = require('express')
const app = express()
const port = 3000
app.post('/', (req, res) => {
res.send('Hello World!")
})
app.listen(port, () => {
console.log('server running')
})
When you run the program in nodejs, open the brower and type http://localhost:3000. The output will be....
Listen for 'end ' the problem will be resolved
Try importing all the dependencies. Importing is better than requiring because you can selectively load only the pieces you need. Also in package.json file add "type":"module" before scripts. The days of const something= require('something') are a thing of the past now because of new ESM modules.
import express from 'express';
import https from 'https';
const app=express();
const port=3000;
In package.json file
"name": "restApiWithNode",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
Read this article for clarity https://formidable.com/blog/2021/node-esm-and-exports/

Trouble getting my node.js server to listen with

I am learning node.js and I am trying to figure out how I can get my program to listen at a specific port, but I just keep getting error messages. Is there any easier way I could be doing this, or what do I need to change in my code to allow this to work?
const http = require('http');
const port = 3000
const requestHandler = (request, response) => {
console.log(request.url)
response.end('server is listening!')
}
const server = http.creatServer(requestHandler)
server.listen(port, (err) => ) {
console.log('server is listening on ${port}')
}
I think you should try something like the following to get started.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World!');
res.end();
}).listen(8080);
Or in your case, I think that the following changes will work:
const http = require('http');
const port = 3000
const requestHandler = (request, response) => {
console.log(request.url)
response.end('server is listening!')
}
const server = http.createServer(requestHandler)
server.listen(port, (err) => {
console.log('server is listening on ${port}')
})
It seems you had a syntax error as well as a typo in your code.

Categories

Resources