Node.js - Static fileserver not working - javascript

I'm trying to create a static fileserver in note.js, but it is not really working.
My fileserver.js code:
var http = require("http"),
sys = require("sys"),
path = require("path"),
url = require("url"),
filesys = require("fs"),
rootpath = "D:\\NodeJS\\WWW\\",
port = 3000;
http.createServer(function(request,response){
var my_path = url.parse(request.url).pathname;
var full_path = path.join(process.cwd(),rootpath+my_path);
path.exists(full_path,function(exists){
if(!exists){
response.writeHeader(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
}
else{
filesys.readFile(full_path, "binary", function(err, file) {
if(err) {
response.writeHeader(500, {"Content-Type": "text/plain"});
response.write(err + "\n");
response.end();
}
else{
response.writeHeader(200);
response.write(file, "binary");
response.end();
}
});
});
})
http.createServer(function(request,response){
var my_path = url.parse(request.url).pathname;
filesys.readFile(rootpath + my_path,response);
}).listen(port);
sys.puts("Server Running on 3000");
When I now try to open: localhost:3000/index.html (The index file is in the folder WWW), my webbrowser is just loading and loading something but not displaying anything. There is also no error in the console.
I hope you can help me!
JS

Are you trying to get directory listing with this program? If yes then use this.
var http = require('http');
var connect = require('connect');
var app = connect()
.use('/public', connect.static(__dirname + '/public'))
.use('/public', connect.directory(__dirname + '/public'))
.use(function(req, res){
res.end('hello world\n');
})
http.createServer(app).listen(3000);
// access it on http://localhost:3000/public
I have used connect module. connect.directory serves the directory listing and connect.static serves the static file.
Let me know if I have not understood you correctly.

Try This :
var fs = require('fs');
var http = require('http');
var path = require("path");
var url = require("url");
var settings = require("../settings");
http.createServer(function (request, response) {
var uri = url.parse(request.url).pathname;
var filetype = (uri.split("/static/")[1]).split(".")[1];
var filename = path.join(process.cwd(), uri);
fs.readFile(filename, function (error, content) {
if (error) {
response.writeHead(500);
response.end();
}
else {
response.writeHead(200, { 'Content-Type': settings.STATIC.HEADERS[filetype.toUpperCase()] });
response.end(content, 'utf-8');
}
});
}).listen(8000);
Add A settings File with something like this :
module.exports = {
DOMAIN: "localhost", // Runnimg Domain , Production Only
PORT: 8080, // Port Project Running On
PROJECT: __dirname, // project directory
DEFAULT_THEME: "default", // Default Theme for site
DB: { // Database Information and Credintials
HOST: "localhost",
USER: 'root',
PASSWORD: 'root',
DATABASE: 'sockets'
},
STATIC: { // Static Files and forlders information
EXTENSIONS: ['psd', 'docs', 'zip', 'rar', 'png'], // allowed to download extensions
HEADERS: {// MIME Types for diffrent types
PDF: 'application/pdf',
CSS: 'text/css',
JS: 'text/javascript',
HTML: 'text/html',
TXT: 'text/plain',
JPG: 'image/jpeg',
JPEG: 'image/jpeg',
GIF: 'image/gif ',
DOWNLOAD: 'application/octet-stream'
}
}
};
i Always like to have this file with everything that i will use everywhere.
and as you can see the code waits for a url like this :
http://domain:port/static/file.ext
you can change that in this line :
var filetype = (uri.split("/static/")[1]).split(".")[1];
Hope this helps

Related

Javascript and CSS don't work in node server

So I'm trying to make a web app, using a node server. I run into a problem where the CSS, Javascript don't work when linking them with a src like or .
The only way I can have css and javascript, is to directly put it inside the script and style parameters, but that doesn't seem that practical
The error that it pulls out shows a url:
127.0.0.1/home.js
why is this happening, and is there a work around?
here is the code
const fetch = require('node-fetch');
const fs = require("fs");
const http = require("http");
const url = require("url");
const server = http.createServer((req, res) => {
// get URL
const pathName = url.parse(req.url, true).pathname;
console.log(pathName);
// create split pathName
const pathSplit = pathName.split("/");
pathSplit.shift();
// HOME PATH
if(pathName === "/home" || pathName === "/"){
// Get HTML data
const data = renderHome();
res.writeHead(200, {"content-type": "text/html"});
fs.readFile(`${__dirname}/templates/template-basic.html`, "utf-8", (err, data) => {
fs.readFile(`${__dirname}/templates/template-battlepass.html`, "utf-8", (err, d) => {
let output = data.replace("{%CONTAINER%}", d);
res.end(output);
});
});
}
// ITEM SHOP PATH
else if(pathName === "/itemShop") {
// Get HTML data
const data = renderItemShop();
res.writeHead(200, {"content-type": "text/html"});
res.end("This is the item shop page");
}
// TOURNAMENTS PATH
else if(pathName === "/tournaments") {
// Get HTML data
const data = renderTournaments();
res.writeHead(200, {"content-type": "text/html"});
res.end("this is the tournaments page");
}
// ITEMS PATH
else if(pathSplit[0] === "items") {
// List all the items for the page
const itemsPages = ["backpacks", "contrails", "emotes", "gliders", "skins", "pickaxes", "wraps"];
let itemConfirm = false;
// If URL has been found, change itemConfirm to true
for(let i = 0; i < itemsPages.length; i++){
if(itemsPages[i] === pathSplit[1]){
// Get HTML data
const data = renderItems(pathSplit[1]);
res.writeHead(200, {"content-type": "text/html"});
res.end(`This is the page for ${pathSplit[1]} in items`);
itemConfirm = true;
}
};
// If itemConfirm is false, no url found
if(itemConfirm === false) {
res.writeHead(404, {"content-type": "text/html"});
res.end(`No URL found for ${pathSplit[1]} in items`);
};
}
// JAVASCRIPT
// NO URL FOUND PATH: 404
else{
res.writeHead(404, {"content-type": "text/html"});
res.end("could not find URL");
}
});
server.listen(1337, "127.0.0.1", () => {
console.log("listening for reqs now");
});
I created a simple server that can serve any type of file using the mime-types library. My basic http server works like this:
const http = require('http');
const fs = require('fs');
const path = require('path');
const mime = require('mime-types'); //Creates the appropriate headerType based on the extension
http.createServer(function (request, response) {
let fileName = path.basename(request.url) || 'index.html' //so that the homepage uses index.html
filePathPart = path.dirname(request.url).slice(1) + "/" + fileName
filePath = "public/" + filePathPart //I store my files in public/js/ or public/css/
console.log(filePath) //just to check if I got the correct files
mimeType = mime.contentType(fileName)
getFile(response, mimeType, filePath)
}).listen(8080);
//I wrote a function to write all the responses the server gives, with this I don't need to expect a specific number of inputs, I can load any number of js/css files or even other html pages.
function getFile(response, mimeType, filePath) {
fs.readFile(filePath, function (err, contents) {
response.writeHead(200, { "Content-Type": mimeType });
response.end(contents);
})
}

why am I being redirected to a 404 Page Not Found?

I wrote the server.js code below:
// Require modules
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
// Array of Mime Types
const mimeTypes = {
"html" : "text/html",
"jpeg" : "image/jpeg",
"jpg" : "image/jpeg",
"png" : "image/png",
"js" : "text/javascript",
"css" : "text/css"
};
// Create Server
const server = http.createServer(function(req, res){
const uri = url.parse(req.url).pathname;
const fileName = path.join(process.cwd(),unescape(uri));
console.log('Loading '+ uri);
const stats;
try{
stats = fs.lstatSync(filename);
} catch(e) {
res.writeHead(404, {'Content-type': 'text/plain'});
res.write('404 Not Found\n');
res.end();
return;
}
// Check if file/directory
if(stats.isFile()){
const mimeType = mimeTypes[path.extname(fileName).split(".").reverse()[0]];
res.writeHead(200, {'Content-type': mimeType});
const fileStream = fs.createReadStream(fileName);
fileStream.pipe(res);
} else if(stats.isDirectory()){
res.writeHead(302,{
'Location' : 'index.html'
});
res.end();
} else {
res.writeHead(500, {'Content-type' : 'text/plain'});
res.write('500 Internal Error\n');
res.end();
}
}).listen(3000);
I have an index.html page that simply says test and instead of rendering that in the browser I get a 404 Page Not Found. Since I tweaked the server.js file I believe the problem is there, but I am not quite sure.
Anybody see how this server code could have been written to better server the index.html file I have in the project?
Perhaps :
stats = fs.lstatSync(fileName);
and not :
stats = fs.lstatSync(filename);
You have the wrong variable/param... it's case sensitive.

Node.js File Upload (Express 4, MongoDB, GridFS, GridFS-Stream)

I am trying to setup a file API in my node.js application. My goal is to be able to write the file stream directly to gridfs, without needing to store the file to disk initially. It seems like my create code is working. I am able to save a file upload to gridfs. The problem is reading the file. When I try to download a saved file via a web browser window, I see that the file contents are wrapped with something like the following:
------WebKitFormBoundarye38W9pfG1wiA100l
Content-Disposition: form-data; name="file"; filename="myfile.txt"
Content-Type: text/javascript
***File contents here***
------WebKitFormBoundarye38W9pfG1wiA100l--
So my question is what do I need to do to strip the boundary information from the file stream before saving it to gridfs? Here's the code i'm working with:
'use strict';
var mongoose = require('mongoose');
var _ = require('lodash');
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = new Grid(mongoose.connection.db);
// I think this works. I see the file record in fs.files
exports.create = function(req, res) {
var fileId = new mongoose.Types.ObjectId();
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: req.query.name,
mode: 'w',
content_type: req.query.type,
metadata: {
uploadedBy: req.user._id,
}
});
writeStream.on('finish', function() {
return res.status(200).send({
message: fileId.toString()
});
});
req.pipe(writeStream);
};
// File data is returned, but it's wrapped with
// WebKitFormBoundary and has headers.
exports.read = function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
// With this commented out, my browser will prompt
// me to download the raw file where I can see the
// webkit boundary and request headers
//res.writeHead(200, { 'Content-Type': file.contentType });
var readstream = gfs.createReadStream({
_id: req.params.id
// I also tried this way:
//_id: file._id
});
readstream.pipe(res);
});
};
By the way, i'm not currently using any middleware for these routes, but am open to doing so. I just didn't want the file to hit the disk prior to being sent to gridfs.
Edit:
Per #fardjad, I added the node-multiparty module for multipart/form-data parsing and it kind of worked. But when I download an uploaded file and compare with an original (as text), there are lots of differences in the encoding, and the downloaded file won't open. Here's my latest attempt.
'use strict';
var mongoose = require('mongoose');
var _ = require('lodash');
var multiparty = require('multiparty');
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = new Grid(mongoose.connection.db);
exports.create = function(req, res) {
var form = new multiparty.Form();
var fileId = new mongoose.Types.ObjectId();
form.on('error', function(err) {
console.log('Error parsing form: ' + err.stack);
});
form.on('part', function(part) {
if (part.filename) {
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: part.filename,
mode: 'w',
content_type: part.headers['content-type'],
metadata: {
uploadedBy: req.user._id,
}
})
part.pipe(writeStream);
}
});
// Close emitted after form parsed
form.on('close', function() {
return res.status(200).send({
message: fileId.toString()
});
});
// Parse req
form.parse(req);
};
exports.read = function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
res.writeHead(200, { 'Content-Type': file.contentType });
var readstream = gfs.createReadStream({
_id: req.params.id
});
readstream.pipe(res);
});
};
Final Edit:
Here's a simple implementation that I copied from another developer and modified. This is working for me: (I'm still trying to figure out why it won't work in my original express app. Something seems to be interfering)
https://gist.github.com/pos1tron/094ac862c9d116096572
var Busboy = require('busboy'); // 0.2.9
var express = require('express'); // 4.12.3
var mongo = require('mongodb'); // 2.0.31
var Grid = require('gridfs-stream'); // 1.1.1"
var app = express();
var server = app.listen(9002);
var db = new mongo.Db('test', new mongo.Server('127.0.0.1', 27017));
var gfs;
db.open(function(err, db) {
if (err) throw err;
gfs = Grid(db, mongo);
});
app.post('/file', function(req, res) {
var busboy = new Busboy({ headers : req.headers });
var fileId = new mongo.ObjectId();
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
console.log('got file', filename, mimetype, encoding);
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: filename,
mode: 'w',
content_type: mimetype,
});
file.pipe(writeStream);
}).on('finish', function() {
// show a link to the uploaded file
res.writeHead(200, {'content-type': 'text/html'});
res.end('download file');
});
req.pipe(busboy);
});
app.get('/', function(req, res) {
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/file" enctype="multipart/form-data" method="post">'+
'<input type="file" name="file"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
});
app.get('/file/:id', function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
if (!file) return res.status(404).send('');
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: file._id
});
readstream.on("error", function(err) {
console.log("Got error while processing stream " + err.message);
res.end();
});
readstream.pipe(res);
});
});
See my comment on the issue you created on github. I had the same problem but I managed to debug the issue. I narrowed it down to where i was confident that the problem was a piece of express middleware modified the request. I disabled my middleware one by one until i found the unlikely culprit: connect-livereload
I commented out app.use(require('connect-livereload')()); and the problem went away.
I believe it was injecting the livereload script into the response (a binary image file).
Looks like the file has been uploaded through an HTML form, in that case you need to decode the multipart/form-data encoded data, re-assemble the parts if needed and save the file to GridFS. For parsing, you can use something like node-multiparty.

Display json file in Browser using Node.JS without file extension

I have made a server using javascript and Node.js that shows a JSON file in my browser.
However, I would like to call the site http://localhost:8888/Test.json without an extension.
For example just: http://localhost:8888/Test
Here is my server code:
var http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs")
port = process.argv[2] || 8888;
file = (__dirname + '/Test.json');
http.createServer(function(req, res) {
var uri = url.parse(req.url).pathname, filename = path.join(process.cwd(), uri);
var contentTypesByExtension = {
'.html': "text/html",
'.css': "text/css",
'.js': "text/javascript",
'.json': "application/json" //Edited due to answer - Still no success :(
};
path.exists(filename, function(exists) {
if(!exists) {
res.writeHead(404, {"Content-Type": "text/plain"});
res.write("404 Not Found\n");
res.end();
return;
}
fs.readFile(file, 'utf8', function (err, file) {
if (err) {
console.log('Error: ' + err);
return;
}
file = JSON.parse(file);
console.dir(file);
var headers = {};
var contentType = contentTypesByExtension[path.extname(file)];
if (contentType) headers["Content-Type"] = contentType;
res.writeHead(200, headers);
res.write(JSON.stringify(file, 0 ,3));
res.write
res.end();
});
});
}).listen(parseInt(port, 10));
console.log("JSON parsing rest server running at\n => http://localhost:" +
port + "/\nPress CTRL + C to exit and leave");
How can I do that?
Should I use routes/express?
Does someone have any suggestions?
Thank you in advance!
Cheers, Vlad
Your problem is probably due to the content type. Having the extension .json is probably triggering your browser to consume it as application/json. So if you remove the extension you need to add the proper Content-Type.
Given that you are already playing around with content types, can't you just add it here, and make sure you write the type for jsons as well?
var contentTypesByExtension = {
'.html': "text/html",
'.css': "text/css",
'.js': "text/javascript",
'.json': "application/json" // <---
};
I've just used the sledgehammer method now with commenting this code fragment out:
if(!exists) {
res.writeHead(404, {"Content-Type": "text/plain"});
res.write("404 Not Found\n");
res.end();
return;
}
Now it works to call just: http://localhost:8888/Test
Cheers, Vlad

Node.js: get path from the request

I have a service called "localhost:3000/returnStat" that should take a file path as parameter. For example '/BackupFolder/toto/tata/titi/myfile.txt'.
How can I test this service on my browser?
How can I format this request using Express for instance?
exports.returnStat = function(req, res) {
var fs = require('fs');
var neededstats = [];
var p = __dirname + '/' + req.params.filepath;
fs.stat(p, function(err, stats) {
if (err) {
throw err;
}
neededstats.push(stats.mtime);
neededstats.push(stats.size);
res.send(neededstats);
});
};
var http = require('http');
var url = require('url');
var fs = require('fs');
var neededstats = [];
http.createServer(function(req, res) {
if (req.url == '/index.html' || req.url == '/') {
fs.readFile('./index.html', function(err, data) {
res.end(data);
});
} else {
var p = __dirname + '/' + req.params.filepath;
fs.stat(p, function(err, stats) {
if (err) {
throw err;
}
neededstats.push(stats.mtime);
neededstats.push(stats.size);
res.send(neededstats);
});
}
}).listen(8080, '0.0.0.0');
console.log('Server running.');
I have not tested your code but other things works
If you want to get the path info from request url
var url_parts = url.parse(req.url);
console.log(url_parts);
console.log(url_parts.pathname);
1.If you are getting the URL parameters still not able to read the file just correct your file path in my example. If you place index.html in same directory as server code it would work...
2.if you have big folder structure that you want to host using node then I would advise you to use some framework like expressjs
If you want raw solution to file path
var http = require("http");
var url = require("url");
function start() {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
source : http://www.nodebeginner.org/
simply call req.url. that should do the work. you'll get something like /something?bla=foo
You can use this in app.js file .
var apiurl = express.Router();
apiurl.use(function(req, res, next) {
var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
next();
});
app.use('/', apiurl);
req.protocol + '://' + req.get('host') + req.originalUrl
or
req.protocol + '://' + req.headers.host + req.originalUrl // I like this one as it survives from proxy server, getting the original host name
Based on #epegzz suggestion for the regex.
( url ) => {
return url.match('^[^?]*')[0].split('/').slice(1)
}
returns an array with paths.
A more modern solution that utilises the URL WebAPI:
(req, res) => {
const { pathname } = new URL(req.url || '', `https://${req.headers.host}`)
}
I've used this const { pathname } = req?._parsedUrl || {}; and it worked for me
Combining solutions above when using express request:
let url=url.parse(req.originalUrl);
let page = url.parse(uri).path?url.parse(uri).path.match('^[^?]*')[0].split('/').slice(1)[0] : '';
this will handle all cases like
localhost/page
localhost:3000/page/
/page?item_id=1
localhost:3000/
localhost/
etc. Some examples:
> urls
[ 'http://localhost/page',
'http://localhost:3000/page/',
'http://localhost/page?item_id=1',
'http://localhost/',
'http://localhost:3000/',
'http://localhost/',
'http://localhost:3000/page#item_id=2',
'http://localhost:3000/page?item_id=2#3',
'http://localhost',
'http://localhost:3000' ]
> urls.map(uri => url.parse(uri).path?url.parse(uri).path.match('^[^?]*')[0].split('/').slice(1)[0] : '' )
[ 'page', 'page', 'page', '', '', '', 'page', 'page', '', '' ]

Categories

Resources