Simple Node.js server without Express - piping HTML files to response - javascript

I am trying my hand at making a simple Node.js server without Express and this where I actually learn a bit more about the down and dirty of actually server files and data on requests based on paths request and basic HTTP stuff.
I have this straightforward server like so:
var http = require('http');
const PORT = 6969;
var allRoutes = require('./routes/all');
var server = http.createServer(allRoutes);
server.listen(PORT, function () {
console.log("Server listening on: http://localhost:%s", PORT);
});
and then I have one "middleware" function like so that handles all requests:
var url = require('url');
var fs = require('fs');
var appRootPath = require('app-root-path');
var path = require('path');
function handleRequest(req, res) {
var requestUrl = url.parse(req.url);
var fsPath;
if (requestUrl.pathname === '/') {
fsPath = path.resolve(appRootPath + '/view/index.html');
}
else {
fsPath = path.resolve(appRootPath + '/view/' + requestUrl.pathname);
}
fs.stat(fsPath, function (err, stat) {
if (err) {
console.log('error occurred...' + err);
return end(req, res);
}
try {
if (stat.isFile()) {
res.writeHead(200);
fs.createReadStream(fsPath).pipe(res);
}
else {
res.writeHead(500);
}
}
finally {
end(req, res);
}
});
}
function end(req, res) {
res.end();
}
module.exports = handleRequest;
the problem I am having is that my function doesn't seem to pipe the response to the browser. The browser shows no evidence of the data come from index.html, which is a barebones .html HTML5 file.
I stole the example, and am surprised it's not really working. Anyone have an idea? I know for sure that the fs.stat function is not experiencing an error and then it is streaming the index.html file, it just doesn't seem to be streaming to the right place...

For starters:
if (requestUrl.pathname = '/')
should be:
if (requestUrl.pathname === '/')
Your code was assigning, not comparing.
In addition, the .pipe() is asynchronous, but you are calling res.end() BEFORE it gets to do it's job in your finally{} block which closes the response stream and stops your pipe from doing anything. By default .pipe() will close the write stream by itself, so you don't need the res.end() at all when using .pipe().
You can change the code to this:
var url = require('url');
var fs = require('fs');
var appRootPath = require('app-root-path');
var path = require('path');
function handleRequest(req, res) {
var requestUrl = url.parse(req.url);
var fsPath;
if (requestUrl.pathname === '/') {
fsPath = path.resolve(appRootPath + '/view/index.html');
}
else {
fsPath = path.resolve(appRootPath + '/view/' + requestUrl.pathname);
}
fs.stat(fsPath, function (err, stat) {
if (err) {
console.log('error occurred...' + err);
return end(req, res);
}
try {
if (stat.isFile()) {
res.writeHead(200);
fs.createReadStream(fsPath).pipe(res);
}
else {
res.writeHead(500);
end(req.res);
}
}
catch(e) {
end(req, res);
}
});
}
function end(req, res) {
res.end();
}
module.exports = handleRequest;

Related

Routing for static site causes endless loading in browser when readFile() is in an if statement

I am trying to create routing for a static site however placing readFile() in an if statement causes infinite loading in my browser and content doesn't load.
I'm trying to do this without the use of Express or any similar framework.
Here is my code:
var http = require("http");
var fs = require("fs");
var url = require("url");
var path = require("path");
var server = http.createServer((req, res) => {
let parsedURL = url.parse(req.url, true);
let fPath = parsedURL.path;
if (fPath === "/") {
fPath = "/index.html";
}
file = path.join(__dirname, "/public" + fPath);
if (fPath === "/index.html") {
fs.readFile(file, (err, data) => {
if (err) {
console.error(err);
res.end("An error has occured.");
} else {
res.end(data);
}
});
} else if (fPath === "/information.html") {
fs.readFile(file, (err, data) => {
if (err) {
console.error(err);
res.end("An error has occured.");
} else {
res.end(data);
}
});
}
});
server.listen(8000);
If if (fPath === "/index.html") { matches and fs.readFile has an error, then you don't send a response.
The same is true for "/information.html".
And if fPath isn't either of those then you get to the end and you don't send a response.
The endless loading is caused by the browser waiting for a response you never send.
You need to make sure that every path through your if statements calls res.end or another function that sends a response to the browser.

Headers, Node.js , Can\'t set headers after they are sent

I'm new in node.js and I'm implementing a Static file server.
what i'm trying to do is just get the file name from the url and display it. running the code id get this error:
_http_outgoing.js:489
throw new Error('Can\'t set headers after they are sent.');
Error: Can't set headers after they are sent.
this is my code
#!/usr/bin/env node
/*
* Basic node.js HTTP server
*/
const http = require('http');
const url = require('url');
const fs = require('fs');
const routes = Object.create(null);
function file(rew, res, serched) {
let fileSerched = serched[serched.length - 1]
fileSerched = __dirname + "/NodeStaticFiles/" + fileSerched;
fs.readFile(fileSerched, function(err, data) {
if (err) {
res.statusCode = 500;
res.end(`Error getting the file: ${err}.`);
} else {
res.setHeader('Content-type', 'text/plain');
res.writeHead(200)
res.end(data);
}
})
}
routes['file'] = file;
function onRequest(req, res) {
const pathname = url.parse(req.url).pathname
const uri = pathname.split('/', 3)[1]
let splittedPathname = pathname.split('/')
splittedPathname.shift()
splittedPathname.shift()
if (typeof routes[uri] === 'function') {
routes[uri](req, res, splittedPathname);
} else {
res.statusCode = 404;
res.end(`File not found!`);
}
res.end()
}
http.createServer(onRequest).listen(3000);
console.log('Server started at localhost:3000')
You need to make sure your code won't call something like res.end() more than once. For example:
function onRequest(req, res) {
const pathname = url.parse(req.url).pathname
const uri = pathname.split('/', 3)[1]
let splittedPathname = pathname.split('/')
splittedPathname.shift()
splittedPathname.shift()
if (typeof routes[uri] === 'function') {
routes[uri](req, res, splittedPathname);
} else {
// THIS WILL CALL res.end() and continue on
res.statusCode = 404;
res.end(`File not found!`);
}
// THIS WILL CALL res.end() AGAIN!!
res.end()
}
try adding a return after you call res.end() in an if/else

Node js works fine but how do I get it on browser?

I have a table in sql Server and I am trying to display it in web browser and apply datatable(jQuery) to it. Below code works fine as it gives the output in command line. But I'd have to get it on the browser(probably in json format).
I am using 'tedious' for connection as that's what I found in Express.js documentation.
var express = require('express');
var app = express();
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var config = {
userName: 'clientinfo',
password: 'clientinfo123',
server: 'USW20051234'
}
var connection = new Connection(config);
connection.on('connect', function (err) {
if (err) {
console.log(err);
} else {
executeStatement();
}
});
function executeStatement() {
request = new Request("SELECT * from dbo.Logs", function (err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount+' rows');
}
connection.close();
});
request.on('row', function (columns) {
columns.forEach(function (column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log(JSON.stringify(column.value));
}
});
});
connection.execSql(request);
}
You need to start HTTP server. As you already define APP try this
app.get('/urltest', (req, res) => {
res.send('hello from nodejs');
});
const PORT = 5000;
app.listen(PORT);
console.log('Listening on :' + PORT + '...');
and try http:localhost:5000/urltest on a browser
Thank You everyone for all the suggestions. I think "tedious" was giving me a hard time so I did npm install mssql and that worked like a charm.
Below is the link I referred to.
http://www.tutorialsteacher.com/nodejs/access-sql-server-in-nodejs

Node.js error "terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc"

I am using node.js on digital ocean and trying to run a file upload / download server.
To make sure the server runs in the background and does not quit on error, I am using the following
nohup nodejs server.js &
I am using nodejs instead of the node command because that is what digital ocean recommends.
This server is almost exlusively for uploading and downloading files. This works, for about two files, but then the server crashes with the following error:
"terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc"
I have no idea what is causing this, and I would appreciate any help. Preventing the crash would be great but also making it so the node server would not crash would also be great. I thought that is what nohup does, but apparently not. (I also haven't been able to get forever working correctly).
Here is the code for my server:
var http = require('http'),
url = require('url'),
util = require('util'),
path = require('path'),
fs = require('fs'),
qs = require('querystring');
var formidable = require('formidable'),
mime = require('mime');
var account = {username: 'test', password: 'etc'};
var accounts = [account],
port = 9090,
function dirTree(filename) {
var stats = fs.lstatSync(filename),
info = {
name: path.basename(filename),
path: ip + ':' + port + '/uploads/finished/' + path.basename(filename),
type: mime.lookup(filename).substring(0, 5)
};
if (stats.isDirectory()) {
info.type = "folder";
info.children = fs.readdirSync(filename).map(function(child) {
return dirTree(filename + '/' + child);
});
}
return info;
}
http.createServer(function(request, response) {
if(request.method.toLowerCase() == 'get') {
var filePath = './content' + request.url;
if (filePath == './content/') {
filePath = './content/home.html';
}
if (filePath == './content/feed') {
a = dirTree('./content/uploads/finished');
response.end(JSON.stringify(a));
}
var extname = path.extname(filePath);
var contentType = mime.lookup(extname);
fs.exists(filePath, function (exists) {
if (exists) {
fs.readFile(filePath, function (error, content) {
if (error) {
response.writeHead(500);
response.end();
}
else {
response.writeHead(200, {'Content-Type': contentType});
response.end(content, 'utf-8');
}
})
} else {
response.writeHead(404);
response.end();
}
});
}
if (request.method.toLowerCase() == 'post') {
var form = new formidable.IncomingForm;
if (request.url == '/verify') {
form.parse(request, function (err, fields, files) {
for (i = 0; i < accounts.length; i++) {
if (fields.username == accounts[i].username && fields.password == accounts[i].password) {
fs.readFile('./content/uploadForm.html', function (error, content) {
if (error) {
response.end('There was an error');
} else {
response.end(content);
}
});
} else {
fs.readFile('./content/invalidLogin.html', function (error, content) {
if (error) {
response.end('There was an error');
} else {
response.end(content);
}
});
}
}
});
} else if (request.url == '/upload') {
var oldPath,
newPath,
fileName;
form.uploadDir = './content/uploads/temp/';
form.keepExtensions = true;
form.parse(request, function (err, fields, files) {
type = files['upload']['type'];
fileName = files['upload']['name'];
oldPath = files['upload']['path'];
newPath = './content/uploads/finished/' + fileName;
});
form.on('end', function () {
fs.rename(oldPath, newPath, function (err) {
if (err) {
response.end('There was an error with your request');
console.log('error')
} else {
response.end('<h1>Thanks for uploading ' + fileName + '<h1>');
}
});
});
}
}
}).listen(port);
console.log('listening on ' + port);
It looks like your script is just run out of the available memory.
Most likely you upload or download very large file and you read complete file in memory while receiving or sending.
You should rewrite you code using stream operations and process files chunk-by-chunk instead.

Saving image to node.js server without express.js

So I have been wondering how to save an image to node.js server without the use of express.(just learning node and want to make everything myself to learn node better, without express).
So far I have a form with the image as only input which I send with a post request. This is what I have so far on my server, which does not log anything.
if(req.method === 'POST') {
if (req.url === '/upload') {
req.on('error', function(e) {
console.log('Problem with request: ' + e.message);
});
res.writeHead(200, {'Content-Type': 'image/jpg; charset=utf8'});
req.on('data', function (chunk) {
fs.writeFile(__dirname + "/uploads/dada.jpg", chunk, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
});
}
}
This is my form:
<form method="post" action="/upload" enctype="multipart/form-data">
EDIT: I fixed most of the problems, but the file is only saved as an image, but cannot be viewed like one. (Something is wrong with the content-type I guess, but don't know how to fix it)
Here is fiddle of my whole app. I know I need to separate it in different modules, but I will do that later
I completely forgot about this old question but now that I see it has quite some views, here is the solution I found:
var port = 1357;
var http = require('http'),
path = require('path'),
mime = require('mime'),
fs = require('fs'),
GUID = require('GUID'),
formidable = require('formidable'),
util = require('util');
var app = http.createServer(function (req, res) {
if (req.method === 'POST') {
if (req.url === '/upload') {
req.on('error', function (e) {
console.log('Problem with request: ' + e.message);
});
var fileDirectory = __dirname + '/db/',
form = new formidable.IncomingForm();
form.keepExtensions = true;
form.uploadDir =fileDirectory;
form.parse(req, function (err, fields, files) {
if (err) throw (err);
var pic = JSON.stringify(util.inspect(files)),
upIndx = pic.indexOf('db'),
path = pic.slice(upIndx + 6, upIndx + 42);
res.writeHead(200, {
'Content-Type': 'text/html'
});
fs.readFile('views/index.html', function (err, page) {
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.write(page);
res.write('<div>Download Link: </div><div>' + fileDirectory + path + '</div>');
res.end();
});
});
}
} else {
//not important for question, handle other request
}
});
app.listen(port);
console.log('Server running on port: ' + port)

Categories

Resources