How can I serve a GZipped file with NodeJS? - node.js

I created simple app used angular elements and http node server. To optimize bundle size i just convert the resulting js file to gz format with current command:
"postbuild": "cat dist/cs6-user-widget/{runtime,polyfills,polyfills-es5,scripts,main}.js | gzip > webcomponent/user-widget.js.gz"
The file is created correctly, but i cannot serve this type of content with my node server:
const http = require('http');
const fs = require('fs');
const hostname = 'localhost';
const port = 4202;
http.createServer((request, response) => {
var contentType = 'text/html';
var filePath = './' + request.url;
fs.readFile(filePath, function(error, content) {
if (error) {
fs.readFile('./index.html', function(error, content) {
response.writeHead(200, { 'content-encoding': 'gzip', 'Content-Type': contentType });
return response.end(content, 'utf-8');
});
} else {
response.writeHead(200, { 'content-encoding': 'gzip', 'Content-Type': contentType });
return response.end(content, 'utf-8');
}
});
});
Can You help me to correctly implement node part?

First, please see this answer
If you still want to use node, here is a simple example:
const express = require("express");
const gzipStatic = require("connect-gzip-static");
const app = express();
app.use(gzipStatic(__dirname));
app.listen(4000);

Related

Server Request Interrupted on Heroku when using Busboy

I am using Busboy to transfer files in my Nodejs app since it supports chunked uploads. When the files are just small sized images upload is working fine but once I'm about uploading videos sometimes it works sometimes it doesn't work and all I keep seeing on my Heroku logs is
H18-Server Request Interrupted.
This is quite draining.
Here is my code:
path = require('path'),
os = require('os'),
fs = require('fs');
var Busboy = require('busboy');
http.createServer(function(req, res) {
if (req.method === 'POST') {
var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
var saveTo = path.join(os.tmpDir(), path.basename(fieldname));
file.pipe(fs.createWriteStream(saveTo));
});
busboy.on('finish', function() {
res.writeHead(200, { 'Connection': 'close' });
res.end("That's all folks!");
});
return req.pipe(busboy);
}
res.writeHead(404);
res.end();
}).listen(8000, function() {
console.log('Listening for requests');
});
How can this be resolved?

Simple no frameworks Node.JS server to host a SPA React App

Here on the the create-react-app site we find an Express tutorial to host a SPA React App (notice the * to return single index.html at every valid path request):
https://create-react-app.dev/docs/deployment
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(9000);
Is there a way to replicate this behaviour on pure Node.js, without frameworks? The way it would handle every valid path, but respond with an error when the path do not exist, etc.. I did not find any information about doing this, is this possible to do with not too much of code or forking Express?
The simple answer is: respond to any GET requests that do not match your MIME types or have no extention, with index.html and handle 404 requests on your front-end.
I followed my lecturer lection and source code - https://github.com/HowProgrammingWorks/ServeStatic - and modified it a little bit to work with React SPA. Posting simplified code here, I hope you get the idea:
const fs = require('fs');
const http = require('http');
const path = require('path');
// postOrder and updateJson are predifined async fucntions.
const postTypes = {
'/api/order': postOrder,
'/api/update_json': updateJson,
};
const STATIC_PATH = path.join(process.cwd(), './public');
const MIME_TYPES = {
html: 'text/html; charset=UTF-8',
js: 'application/javascript; charset=UTF-8',
css: 'text/css',
json: 'application/json',
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
ico: 'image/x-icon',
svg: 'image/svg+xml',
};
const serveFile = name => {
const filePath = path.join(STATIC_PATH, name);
if (!filePath.startsWith(STATIC_PATH)) {
console.log(`Can't be served: ${name}`);
return null;
}
const stream = fs.createReadStream(filePath);
console.log(`Served: ${name}`);
return stream;
};
http
.createServer(async (req, res) => {
const { url } = req;
if (req.method === 'GET') {
const fileExt = path.extname(url).substring(1);
const mimeType = MIME_TYPES[fileExt] || MIME_TYPES.html;
res.writeHead(200, { 'Content-Type': mimeType });
const stream = fileExt === '' ? serveFile('/index.html') : serveFile(url);
if (stream) stream.pipe(res);
} else if (req.method === 'POST') {
const postType = postTypes[url];
let response = postType ? await postType(req) : `Woops, no ${url} post type!`;
res.writeHead(response ? 200 : 500, { 'Content-Type': 'text/plain' });
response ||= `Woops, your response failed to arrive!`;
res.end(response);
}
})
.listen(3000);

Is there a way to provide file for download using only Node without using express like below?

app.get('/download', function(req, res){
const file = `${__dirname}/upload-folder/dramaticpenguin.MOV`;
res.download(file); // Set disposition and send it.
});
Here's a super simple example that should give you a start on how to implement this without express:
const http = require('http');
const fs = require('fs');
const path = require('path');
const httpServer = http.createServer(requestResponseHandler);
function requestResponseHandler(req, res) {
if (req.url === '/download') {
const file = `${__dirname}/sample-video.mov`;
res.writeHead(200, {
'Content-Type': 'video/quicktime',
'Content-Disposition': 'attachment; filename="sample.mov',
});
fs.createReadStream(file).pipe(res);
}
}
httpServer.listen(3000, () => {
console.log('server is listening on port 3000');
});
Basically all it does is to set the correct content-type and content-disposition headers and the create a read-stream from the mov-file and pipe this stream into the response-object.

NodeJS - Server Side File Upload Handler

i'm trying to develop a simple file upload handler.
the only thing that i want is , this app receives a file from client and saves on hdd.
(i don't want to upload a file with nodejs , i just want to receive a file upload post and save it on my hdd)
how can i do this ?
i'm tried this way but , it does not works as expected.
var http = require('http'),
path = require('path'),
os = require('os'),
fs = require('fs');
var Busboy = require('busboy');
http.createServer(function(req, res) {
if (req.method === 'POST') {
try{
var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
var fstream = fs.createWriteStream('asdasd');
file.pipe(fstream);
fstream.on('close', function () {
res.writeHead(200, { 'Connection': 'close' });
res.send('upload succeeded!');
});
/*var saveTo = path.join(os.tmpDir(), path.basename(fieldname));
file.pipe(fs.createWriteStream('./output.asdasd'));
fstream.*/
});
busboy.on('finish', function() {
res.writeHead(200, { 'Connection': 'close' });
res.end("That's all folks!");
});
return req.pipe(busboy);
}
catch(err){
console.log('error : ' + err);
res.writeHead(404);
res.end();
}
}
res.writeHead(404);
res.end();
}).listen(4842, function() {
console.log('Listening for requests');
});
I've never used busboy before but the example given over in their GitHub documentation works fine.
let http = require('http'),
path = require('path'),
os = require('os'),
fs = require('fs');
let Busboy = require('busboy');
http.createServer(function (req, res) {
if (req.method === 'POST') {
let busboy = new Busboy({ headers: req.headers });
// handle all incoming `file` events, which are thrown when a FILE field is encountered
// in multipart request
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
// figure out where you want to save the file on disk
// this can be any path really
let saveTo = path.join(os.tmpdir(), path.basename(filename));
// output where the file is being saved to make sure it's being uploaded
console.log(`Saving file at ${saveTo}`);
// write the actual file to disk
file.pipe(fs.createWriteStream(saveTo));
});
busboy.on('finish', function () {
res.writeHead(200, { 'Connection': 'close' });
res.end("That's all folks!");
});
return req.pipe(busboy);
}
res.writeHead(404);
res.end();
}).listen(8000, function () {
console.log('Listening for requests');
});
I've added some comments in the relevant section to make it more clear how it works. If you need more details, just comment below and I'll add them.
Simply use the FS api from node to write data received on file ? :)
https://nodejs.org/api/fs.html#fs_class_fs_writestream
Solved ,
i'm tried it with postman , i changed my mind and tried it with RESTClient , it works successfully now :)

Nodejs send data in gzip using zlib

I tried to send the text in gzip, but I don't know how. In the examples the code uses fs, but I don't want to send a text file, just a string.
const zlib = require('zlib');
const http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html', 'Content-Encoding': 'gzip'});
const text = "Hello World!";
res.end(text);
}).listen(80);
You're half way there. I can heartily agree that the documentation isn't quite up to snuff on how to do this;
const zlib = require('zlib');
const http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html', 'Content-Encoding': 'gzip'});
const text = "Hello World!";
const buf = new Buffer(text, 'utf-8'); // Choose encoding for the string.
zlib.gzip(buf, function (_, result) { // The callback will give you the
res.end(result); // result, so just send it.
});
}).listen(80);
A simplification would be not to use the Buffer;
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html', 'Content-Encoding': 'gzip'});
const text = "Hello World!";
zlib.gzip(text, function (_, result) { // The callback will give you the
res.end(result); // result, so just send it.
});
}).listen(80);
...and it seems to send UTF-8 by default. However, I personally prefer to walk on the safe side when there is no default behavior that makes more sense than others and I can't immediately confirm it with documentation.
Similarly, in case you need to pass a JSON object instead:
const data = {'hello':'swateek!'}
res.writeHead(200, {'Content-Type': 'application/json', 'Content-Encoding': 'gzip'});
const buf = new Buffer(JSON.stringify(data), 'utf-8');
zlib.gzip(buf, function (_, result) {
res.end(result);
});

Resources