How to download a file hosted on http webserver in nodejs - html

I have created a nodejs http webserver to host some files -
var http = require('http'),
fs = require('fs');
var finalhandler = require('finalhandler');
var serveStatic = require('serve-static');
var qs = require('querystring');
var serve = serveStatic("./");
fs.readFile('./index.html', function (err, html) {
if (err) {
throw err;
}
http.createServer(function(req, res) {
var done = finalhandler(req, res);
serve(req, res, done);
if(req.method === "POST") {
if (req.url === "/downloadInstaller") {
var requestBody = '';
req.on('data', function(data) {
requestBody += data;
if(requestBody.length > 1e7) {
res.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'});
res.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>');
}
});
req.on('end', function() {
fs1.readFile("./FileToDownload.zip", function(err, data)
{ res.statusCode = 200;
res.setHeader('Content-type', 'text/plain' );
res.write(data);
return res.end();
});
});
}
}
}).listen(8000);
});
Its working good . I can download a file when I hit url - http://localhost:8000/fileToDownload.extension
Now , my index.html looks like -
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<form action="/downloadInstaller" method="post">
<label>OS Flavor : </Label>
<input type="text" id="os" name="os"/>
<input type="submit"/>
</form>
I want to download same file when I will click on submit button.I have written the code for same. But it renders the file in browser instead of downloading it.
How Can i achieve it in nodejs?
Considerably new in nodejs.
Thanks

You should remove this :
res.setHeader('Content-type', 'text/plain' );
And replace it with headers hinting the browser that it should download the file:
res.setHeader('Content-Description', 'File Transfer');
res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Type', 'application/force-download'); // only if really needed
res.setHeader('Content-Disposition', 'attachment; filename=FileToDownload.zip');
NB: the "force-download" header is a dirty hack, try without it first.

Related

html post method always failing

I made an html based on a course I was studying and was trying out post method using ajax. I made a web server using node js and hosted it on a port so that I can send a JSON file and receive it from there but it is always failing. This is my code on my html for the post method.
$.post('http://localhost:8000', message).done(function(received) {
$('#output').text('You chose ' + received.value + ' out of ' + received.maxValue)
}).fail(function () {
$('#output').text('Failed')
})
It is always failing, hope to get some ideas because I was studying html and just needed to make a quick server to test using post requests on.
It worked when I hosted the html on the node.js server on the same port. I am tying to see how to make it work while not being on the same port or server.
Here's my server side code:
var http = require('http'),
fs = require('fs'),
path = require('path')
var PORT = 8000
fs.readFile(path.resolve(__dirname, "index.html"), function(err, html) {
if (err) {
throw err;
}
http.createServer(function(request, response) {
if (request.url == '/home') {
response.writeHeader(200, {
"Content-Type": "text/html"
});
response.write(html);
response.end();
}
if (request.method == 'POST') {
console.log('POST2')
var body = ''
request.on('data', function(data) {
body += data
});
request.on('end', function() {
try {
var post = JSON.parse(body);
console.log(post);
response.writeHead(200, {
'Content-Type': 'application/json'
});
response.write(JSON.stringify(post))
response.end();
return;
} catch (err) {
var post = JSON.parse(body);
// deal_with_post_data(request,post);
response.writeHead(200, {
'Content-Type': 'application/json'
});
response.write(body);
response.end();
return;
}
});
}
}).listen(PORT);
});
console.log('Node.js web server at port ' + PORT + ' is running..')

CSS loads but doesn't do anything

I'm trying to make a basic multiplayer game with Socket.IO, p5.js and NodeJS, hosting it on Replit.
I have a basic httpServer with socket.io, and it serves the HTML, CSS and JavaScript files fine. But when I put the <link> tag in the HTML to load the CSS, the CSS loads fine (I can see it in the Sources tab in the Chrome DevTools) but it doesn't actually apply to the HTML.
The code is here, but I'll put it here as well.
index.js The main NodeJS file
const { readFileSync } = require('fs');
const { createServer } = require('http');
const { Server } = require('socket.io');
const httpServer = createServer((req, res) => {
const r = /^\/?(index\.(html|css|js))?$/i;
if (!r.test(req.url))
{
res.writeHead(404);
res.end('Not found');
return;
}
const m = req.url.match(r);
// reload the file every time
const content = readFileSync(__dirname + '/public/' + (m[1] || 'index.html'));
const length = Buffer.byteLength(content);
res.writeHead(200, {
'Content-Type': 'text/html',
'Content-Length': length,
});
res.end(content);
});
const io = new Server(httpServer, {
// Socket.IO options
});
let players = {};
io.on('connection', (socket) => {
players[socket.id] = {
id: socket.id,
x: 0,
y: 0
};
socket.on('disconnect', (reason) => {
delete players[socket.id];
});
});
io.on('data', data => {
players[data.id].x += data.x;
players[data.id].y += data.y;
});
setInterval(() => {
io.sockets.emit('data', players);
}, 1000 / 60);
httpServer.listen(6001);
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Multiplayer Online IO Game 2</title>
<link rel="stylesheet" href="index.css">
<script src="/socket.io/socket.io.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js" integrity="sha512-N4kV7GkNv7QR7RX9YF/olywyIgIwNvfEe2nZtfyj73HdjCUkAfOBDbcuJ/cTaN04JKRnw1YG1wnUyNKMsNgg3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="/index.js" defer></script>
</head>
<body>
</body>
</html>
public/index.css
body
{
margin: 0px;
overflow: hidden;
}
canvas
{
display: none;
}
The canvas' display: none was to see if the CSS actually did anything, but it doesn't.
public/index.js The client JavaScript
let ID = null;
let players = {};
const socket = io({
// Socket.IO options
});
socket.on('connect', () => {
ID = socket.id;
});
socket.on('connect_error', (err) => {
alert(`There was an error connecting to the WebSocket server:\n${err.message}`);
});
socket.on('data', (data) => {
players = data;
});
function setup()
{
createCanvas(windowWidth, windowHeight);
}
function draw()
{
background(255);
fill(0);
for (const id of Object.keys(players))
{
const player = players[id];
circle(player.x, player.y, 10);
}
}
Your server is using the content type text/html for all responses regardless of the type of file being returned. Some web browsers are strict about content-types and will not process a stylesheet if it has the wrong content type. Here's a example fix:
const httpServer = createServer((req, res) => {
const r = /^\/?(index\.(html|css|js))?$/i;
if (!r.test(req.url))
{
res.writeHead(404);
res.end('Not found');
return;
}
const m = req.url.match(r);
// reload the file every time
const content = readFileSync(__dirname + '/public/' + (m[1] || 'index.html'));
const length = Buffer.byteLength(content);
res.writeHead(200, {
// Determine the content type based on the file extension
'Content-Type': m[2] ? getContentType(m[2]) : 'text/html',
'Content-Length': length,
});
res.end(content);
});
function getContentType(ext) {
switch (ext.toLowerCase()) {
case 'html':
return 'text/html';
case 'css':
return 'text/css';
case 'js':
return 'text/javascript';
default:
return 'application/octet-stream';
}
}
You might want to consider using a more full-featured HTTP server such as express instead of rolling your own.

What does the URL argument do in the xhr.open() function?

I am writing some server software, and I have tested it using a very simple HTML file. It doesn't seem to make any difference what the URL argument is when I open a new XMLHttpRequest POST request. Can anyone tell me? Here is the code if it helps:
Browser HTML file:
<!DOCTYPE html>
<html>
<body>
<title>This is a title!</title>
<p id="paragraph">
Hello World!
</p>
<script>
setTimeout(() => {
var http = new XMLHttpRequest();
var jsonToSend = {
"name": "Steve Smith",
"age": 25,
"isMale": true
};
http.open("POST", "", true);
http.setRequestHeader("Content-Type", "application/json");
http.send(JSON.stringify(jsonToSend));
}, 3000);
</script>
</body>
</html>
Server code (node.js)
const http = require("http");
const fs = require("fs");
const port = 80;
http.createServer((request, response) => {
if (request.method == "GET") {
try {
var newUrl = request.url.substring(1);
if (request.url == "/") {
newUrl = "test.html";
}
response.writeHead(200, "OK", {"Content-Type": "text/html"});
response.write(fs.readFileSync(newUrl).toString());
} catch (error) {
response.writeHead(404, "Not Found", {"Content-Type": "text/html"});
response.write("<h1>404 not found</h1>");
}
response.end();
} else if (request.method == "POST") {
var body = "";
request.on("data", (chunk) => {
body += chunk.toString();
});
request.on("end", () => {
console.log(JSON.parse(body));
response.statusCode = 200;
response.end(body);
});
}
console.log(request.method + ":");
console.log(" URL: " + request.url);
console.log(" Status code: " + response.statusCode);
}).listen(port, () => {
console.log("Listening on port " + port);
});
It sets the URL the request is made to.
It only doesn't seem to make a difference because you're written a webserver which doesn't pay attention to the URL for POST requests.

How to serve static files in vanilla nodeJS

To preface this, I am currently learning how to use vanilla nodeJS to host html files for a personal project. I am using the following code to do this. I realize that in order to display images with html I need to publicly serve the files; however, I am not sure how to do this with the provided code below. I appreciate any feedback and contributions on how to achieve this.
var http = require("http");
var url = require("url");
var fs = require("fs");
var server = http.createServer(function (request, response) {
var path = url.parse(request.url).pathname;
switch (path) {
case "/homepage.html":
fs.readFile(__dirname + path, function(error, data) {
if (error) {
response.writeHead(404);
response.write(error);
response.end();
} else {
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
}
});
break;
case "/page1.html":
fs.readFile(__dirname + path, function(error, data) {
if (error) {
response.writeHead(404);
response.write(error);
response.end();
} else {
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
}
});
break;
default:
response.writeHead(404);
response.write("Oops this doesn't exist!");
response.end();
}
});
server.listen(8008);
console.log("Server is running on port 8008");
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
</head>
<body>
<div class = "row">
<div class = "col-sm-4">
<img src = "/image.jpg/" class = "img-fluid" class = "rounded-circle">
</div>
<div class = "col-sm-8">
</div>
</body>
</html>
Hei, try this piece of code:
var http = require("http");
var url = require("url");
var fs = require("fs");
var server = http.createServer(function (request, response) {
var path = url.parse(request.url).pathname;
switch (path) {
case "/homepage.html":
fs.readFile(__dirname + path, function(error, data) {
if (error) {
response.writeHead(404);
response.write(error);
response.end();
} else {
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
}
});
break;
case "/page1.html":
fs.readFile(__dirname + path, function(error, data) {
if (error) {
response.writeHead(404);
response.write(error);
response.end();
} else {
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
}
});
break;
default:
// response.writeHead(404);
// response.write("Oops this doesn't exist!");
// response.writeHead(200, {'Content-Type':'text/html'});
// response.write(data);
console.log('I am here for path ', path);
fs.readFile(__dirname + path, function(error, data) {
if (error) {
response.writeHead(404);
response.write(error);
response.end();
} else {
response.writeHead(200, {'Content-Type':'image/jpg'});
response.write(data);
response.end();
}
});
}
});
server.listen(8008);
console.log("Server is running on port 8008");
So, because for the image you did not have a case in your switch the default was used.
I specified in the default case what to do.
As you can see if you end up with 100 static files you have to specify a case for each and every file.
Note that the example above will work only for jpg images .
This will be very hard to maintain and not recomended because it will (possibly) mix your statics with the website's logic.
The easiest way to achieve what you want is to use express module, it already has this functionality and it is very, very easy to use.
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/mystaticcontent'));
app.use('/hiddenfolder', express.static(__dirname+'/mystaticcontent/'));
app.listen(8008);
For the first app.use(express.static(__dirname + '/mystaticcontent')); if you put image.jpg in this folder, you can access it using this url: http://localhost:8008/image.jpg
Here app.use('/hiddenfolder', express.static(__dirname+'/mystaticcontent/')); you hide the real name of the folder , the image is accessible at http://localhost:8008/hiddenfolder/image.jpg
If you don't want to use express, maybe you should have a look at https://www.npmjs.com/package/serve-static get inspired about how to write your own statics module.
Hope it helps!
*** I have found an easier way to serve static files using node-static library
provided in nodejs docs ***
var static = require('node-static');
var http = require('http');
var file = new(static.Server)(__dirname);
http.createServer(function (req, res) {
file.serve(req, res);
}).listen(8080);
A link to the same is here NODE JS Docs

Getting html form data using http

I need to get data from simple html form (code below) and send it to API (http://netology.tomilomark.ru/doc/#api-ND) that makes hash out of it.
Here is html form code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Form</title>
</head>
<body>
<form action="/sendForm">
Name:<br>
<input type="text" name="firstName" value="">
<br>
Surname:<br>
<input type="text" name="lastName" value="">
<br><br>
<input type="submit" value="Send">
</form>
</body>
And that's what I´ve got on the server side:
"use strict";
const http = require("http");
const fs = require("fs");
const PORT = 3000;
let resObject = {};
let hash;
// Code that sends name + surname to the API and creates hash
// ------------- begin -------------
let options = {
hostname: "netology.tomilomark.ru",
path: "/api/v1/hash",
method: "POST",
headers: {
"firstName": "Evgeny",
"Content-Type": "application/json"
}
};
let req = http.request(options, (res) => {
let resString = "";
res.on("data", (data) => {
resString += data;
});
res.on("end", () => {
console.log(resString);
hash = resString["hash"];
})
});
let reqMessage = JSON.stringify({"lastName": "Kobzev"});
req.write(reqMessage);
req.end();
resObject.firstName = "Evgeny";
resObject.lastName = "Kobzev";
console.log(JSON.stringify(resObject));
// -------------- end --------------
// Create web server that loads the html file
// ------------- begin -------------
const server = http.createServer((req, res) => {
fs.readFile("./logs/form.html", (err, file) => {
res.writeHead(200, {'Content-Type': 'text/html','Content-Length':file.length});
res.write(file);
});
});
server.on("error", (err) => console.error(err));
server.on("listening", () => console.log(`Start HTTP on port ${PORT}`));
server.listen(PORT);
// -------------- end --------------
How can I get data from that simple form and later send it to API? The problem is that I need to use a low level abstraction solution: http and maybe querystring.
Any help will be appreciated!
After working for few minutes I get the code.Here in my code I am printing hash values in terminal.And here is my code
var qs = require('querystring');
var request=require('request');
var util=require('util');
const http= require("http");
const fs= require("fs");
var hash=require('object-hash');
const server = http.createServer((req, res) => {
if (req.url === '/sendForm' && req.method === 'POST') {
var body = "";
req.on('data', function (chunk) {
body += chunk;
});
req.on('end', function () {
var post= qs.parse(body);
var Fs=hash({NAME:post.firstName});
var Sn=hash({SURNAME:post.surName});
console.log("FirstName:"+post.firstName);
console.log("SurName:"+post.surName)
console.log("Hashed Value Of FirstName:"+Fs);
console.log("Hashed Value Of SurName:"+Sn);
res.end("successfully submitted");
});
}
fs.readFile("./sample.html", (err, file) => {
res.writeHead(200, {'content-type': 'text/html','Content-Length':file.length});
res.end(file);
});
}).listen(3000,function(){
console.log("Server Listening on 3000");
});
Hope this helps for you...