Displaying html with images using fs - html

I need to display in my server an html containing some text and stuffs, which are not important here, and the first image found inside the folder given as parameter.
I found another answer where fs.readFile was used to retrieve the html file drectly, with the image already in there, but in this case I need to build an html for every image.
I've tried this, but it doesn't show any image:
var http = require('http');
const fs = require('fs');
function read_dir(req, res, path="./images") {
let image_urls = fs.readdirSync(path);
let src = path.split("").slice(1).join("");
let image = `<img id="image" src="http://localhost:8888${src}/${image_urls[0]}">`;
res.end(image);
}
function onrequest(request, response) {
// Programs what is going to be sent back to the browser.
console.log("HTTP request received");
// Parses command line arguments
var myArgs = process.argv.slice(2);
response.writeHead(200,
{"Content-Type": 'text/html'}
);
response.write(`<h1>SLIDESHOW AREA</h1>`);
read_dir(request, response, myArgs[0]);
}
// The http.createServer() method turns my computer into an HTTP server.
var server = http.createServer(onrequest);
// The server.listen() method creates a listener on the specified port or path.
// server.listen(port, hostname, backlog, callback);
server.listen(8888);
console.log("Listening on http://localhost:8888/");

Okay, so I found out what was missing. If you're one like me that understand really poorly servers, this might be helpful.
<img src="http://localhost:8888/image/jpeg/campus1.jpg">
When the server reads the image src, it sends a GET request with url /image/jpeg/campus1.jpg. Right now the server can display HTML elements, but it cannot display JPEG elements, which is fundamental here.
It's really subtle, the image has to be read from its folder, and be set up correctly before it can be displayed.
So, the correct way to do it is to make a route inside the server that reads images and tells the server that they are of type 'image/jpeg'. At that point, the images are ready and baked to be read by the HTML.
var http = require('http');
const fs = require('fs');
let routes = { "/": main, "/image": fileRouter }
function main(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write("<h1>HI</h1>");
res.write("<h2>Here's an image</h2>");
res.end(`<img src="http://localhost:8888/image/jpeg/campus1.jpg">`);
}
function fileRouter(req, res) {
let path = req.url;
console.log(path);
fs.readFile("."+path, function(err, data) {
if(err) {
res.writeHead(500, { 'Content-Type' : 'text/plain' });
res.end('500 - Internal Error');
} else {
res.writeHead(200, { 'Content-Type' : 'image/jpeg' });
res.end(data);
}
});
}
function onrequest(req, res) {
//Parse Request
let url = req.url;
let route = url.split("/")[1];
console.log(req.method, req.url);
//Route Request
if (typeof routes["/" + route] === 'function') {
routes["/" + route](req, res);
} else {
res.writeHead(404); //not found
res.end();
}
}
var server = http.createServer(onrequest);
server.listen(8888);
I wish programming wouldn't require always my head to get dislodged, things don't always make sense, I don't get sometimes why people designed things this way. But well, also love's not always easy. Have a nice day everyone!

This tag <img id="image" src="http://localhost:8888${src}/${image_urls[0]}"> are trying to access to your server a the "http://localhost:8888${src}/${image_urls[0]}" url.
So you need to serve it for the browser to be able to download it.
An jpeg image is served with the 'Content-type: image/jpeg'header, but in the case of large images you need to make a more complex work, like cache memory, streaming, things like that; or the load time of your page will drop down easily.
It is recomended to use services like cloudinary to serve this type of content.

Related

How to use a Javascript file to refresh/reload a div from an HTML file?

I am using Node JS and have a JS file, which opens a connection to an API, works with the receving API data and then saves the changed data into a JSON file. Next I have an HTML file, which takes the data from the JSON file and puts it into a table. At the end I open the HTML file in my browser to look at the visualized table and its data.
What I would like to happen is, that the table (or more specific a DIV with an ID inside the table) from the HTML file refreshes itself, when the JSON data gets updated from the JS file. Kinda like a "live table/website", that I can watch change over time without the need to presh F5.
Instead of just opening the HTML locally, I have tried it by using the JS file and creating a connection with the file like this:
const http = require('http');
const path = require('path');
const browser = http.createServer(function (request, response) {
var filePath = '.' + request.url;
if (filePath == './') {
filePath = './Table.html';
}
var extname = String(path.extname(filePath)).toLowerCase();
var mimeTypes = {
'.html': 'text/html',
'.css': 'text/css',
'.png': 'image/png',
'.js': 'text/javascript',
'.json': 'application/json'
};
var contentType = mimeTypes[extname] || 'application/octet-stream';
fs.readFile(filePath, function(error, content) {
response.writeHead(200, { 'Content-Type': contentType });
response.end(content, 'utf-8');
});
}).listen(3000);
This creates a working connection and I am able to see it in the browser, but sadly it doesn't update itself like I wish. I thought about some kind of function, which gets called right after the JSON file got saved and tells the div to reload itself.
I also read about something like window.onload, location.load() or getElementById(), but I am not able to figure out the right way.
What can I do?
Thank you.
Websockets!
Though they might sound scary, it's very easy to get started with websockets in NodeJS, especially if you use Socket.io.
You will need two dependencies in your node application:
"socket.io": "^4.1.3",
"socketio-wildcard": "^2.0.0"
your HTML File:
<script type="module" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>
Your CLIENT SIDE JavaScript file:
var socket = io();
socket.on("update", function (data) { //update can be any sort of string, treat it like an event name
console.log(data);
// the rest of the code to update the html
})
your NODE JS file:
import { Server } from "socket.io";
// other code...
let io = new Server(server);
let activeConnections = {};
io.sockets.on("connection", function (socket) {
// 'connection' is a "magic" key
// track the active connections
activeConnections[socket.id] = socket;
socket.on("disconnect", function () {
/* Not required, but you can add special handling here to prevent errors */
delete activeConnections[socket.id];
})
socket.on("update", (data) => {
// Update is any sort of key
console.log(data)
})
})
// Example with Express
app.get('/some/api/call', function (req, res) {
var data = // your API Processing here
Object.keys(activeConnections).forEach((conn) => {
conn.emit('update', data)
}
res.send(data);
})
Finally, shameful self promotion, here's one of my "dead" side projects using websockets, because I'm sure I forgot some small detail, and this might help. https://github.com/Nhawdge/robert-quest

Return image from Node REST API and use in img.src on client-side

I am storing images in MongoDB as base64 string. I created Express route to get image by id:
router.get('/:userId/images/:imgId', (req, res) => {
Image.findOne(
{ _id: req.params.imgId },
(err, img) => {
if (err) {
res.status(500).send('someErr');
} else {
var resultImg = Buffer.from(img.data, 'base64');
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-Length': resultImg.length
});
res.end(resultImg);
}
}
);
});
Client-side:
<img src={`api/users/${userId}/images/${imgId}`} />
What I am sure about:
path is correct, server receives request and returns 200 response
data is correctly fetched from MongoDB
base64 string is correct (when I copy paste to verifier like https://codebeautify.org/base64-to-image-converter, it is working)
Why images are not loaded?
make sure the output has this string at the beginning
<img src='data:image/png;base64,your base 64 goes here'/>
you can test by copying the output and put it in a static html and see does it work.
so may be something like this would help
<img src=`data:image/png;base64,{`api/users/${userId}/images/${imgId}`}`/>
Have you try hit your backend using AJAX or Fetch API ?
After that, you can load response from that API into your image element

How do I get the same formating in my email as on my website?

I've made a website where you fill out a form and then it saves the form data into a JSON file. The data is shown on the site like this:
After that, I send the data in an email. But the email is formatted like this:
How do I get the email to have the same format as the website does? I suspect that the formatting changes where I save the data to the JSON file and then read it again. But I'm not sure and if it is I don't know how to fix it.
Here is the code:
var fs = require('fs')
var formidable = require("formidable")
var util = require('util')
var mailFunctions = require('./mailFunction.js');
'use strict';
function processAllFieldsOfTheForm(req, res) {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
res.writeHead(200, {
'content-type': 'text/plain'
});
res.write('received the data:\n\n');
res.end(util.inspect( {
fields: fields,
files: files
}));
});
}
function processFormFieldsIndividual(req, res) {
var fields = [];
var form = new formidable.IncomingForm();
form.on('field', function (field, value) {
fields.push([field, value]);
});
// Display data to user
form.on('end', function() {
var objectToJSON = JSON.stringify({
fields: fields
}, null, 2)
fs.writeFile('C:/Users/admin/Desktop/Node.js/test/source/json/answers.json', objectToJSON, (err) => {
if (err) {
console.log(err);
console.log('Error while writing file')
throw err;
}
})
res.writeHead(200, {
'content-type': 'text/plain'
});
res.write('received the data: \n\n');
res.end(util.inspect( {
fields: fields
}));
});
// Returns data inside file
form.on('end', function() {
fs.readFile('C:/Users/admin/Desktop/Node.js/test/source/json/answers.json', (err, data) => {
if (err) {
console.log(err)
console.log('Error while reading file')
throw err;
}
else {
mailFunctions.makeMail(data)
}
});
});
form.parse(req);
}
I'm also kinda new to node.js so there is probably so useless/bad code in there.
You didn't include the only relevant part of your source code (the mailFunction.js file) so it's impossible to tell you what's wrong with it. (Also, what's with the screenshots? Are we supposed to use photoshop to fix it? If developers has lost the ability to copy and paste code then there is no hope.)
Now, it's also impossible to tell you how to make an email that looks like your website when we don't know how your website looks like, isn't it, and all that can be said here is a very general advice.
You need to use some templating system to produce HTML (I assume it's HTML but it's also possible that all you need is plain text - again, it's impossible to tell from your question) and you need to make sure that that HTML is correctly formatted for emails - which is quite different than formatting for websites, something that a lot of people don't know.
Then you need to correctly send the HTML email along with all of the attachments because you cannot reliably reference images and other assets hosted on your servers.
There are good modules on npm that can help you with all of those steps. For sending the mail you can use Nodemailer:
https://www.npmjs.com/package/nodemailer
To use templating with Nodemailer, see:
https://community.nodemailer.com/2-0-0-beta/templating/
To send the email it's best to use a transactional email service like Mandrill, Mailgun or Amazon SES if you don't want getting blocked by your ISP and your mail going to spam folders of your users. See:
http://www.mandrill.com/
https://www.mailgun.com/
https://aws.amazon.com/ses/
All of those are supported by Nodemailer.
To know how to format the actual HTML and CSS for your emails to look like you want, see those tutorials:
https://templates.mailchimp.com/getting-started/html-email-basics/
http://blog.mailgun.com/building-html-email-and-workflow-tips/
http://blog.mailgun.com/transactional-html-email-templates/

Sending nested object via post request

I'm running this little node express server, which is supposed to check if the voucher is valid later and then send an answer back to the client
this is my code
app.post('/voucher', function (request, response) {
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
if ( request.method === 'OPTIONS' ) {
response.writeHead(200);
response.end();
return;
}
console.log(request)
let results;
let body = [];
request.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
results = Buffer.concat(body).toString();
// results = JSON.parse(results);
console.log('#### CHECKING VOUCHER ####', results)
let success = {success: true, voucher: {name: results,
xxx: 10}}
success = qs.escape(JSON.stringify(success))
response.end(success)
} )
}
);
It is obviously just an example and the actual check is not implemented yet. So far so good.
Now on the client side where I work with REACT, I can not seem to decode the string I just send there.
there I'm doing this
var voucherchecker = $.post('http://localhost:8080/voucher', code , function(res) {
console.log(res)
let x = JSON.parse(res)
console.log(x)
console.log(qs.unescape(x))
It gives me the error
Uncaught SyntaxError: Unexpected token % in JSON at position 0
When I do it the other way arround
let x = qs.unescape(res)
console.log(x)
console.log(JSON.parse(x))
Than it tells me
Uncaught TypeError: _querystring2.default.unescape is not a function
Maybe you can help me? I don't know what the issue is here. Thank you.
Also another question on this behalf, since I'm only a beginner. Is there smarter ways to do such things than I'm doing it now? I have react which renders on the client and I have a mini express server which interacts a few times with it during the payment process.
The both run on different ports.
What would be the standard way or best practice to do such things?
I'm a bit perplexed as to why your backend code has so much going on in the request.
Since you asked for if there is a different way to write this, I will share with you how I would write it.
Server
It seems that you want your requests to enable CORS, it also seems that you originally wanted to parse a JSON in your request body.
This is how I would recommend you re-write your endpoint
POST /voucher to take a request with body JSON
{
code: "xxxxx"
}
and respond with
{
success: true,
voucher: {
name: results,
xxx: 10
}
}
I would recommend you use express's middleware feature as you will probably use CORS and parse JSON in most your requests so in your project I would.
npm install body-parser
npm install cors
then in your app initialization
var bodyParser = require('body-parser')
var cors = require('cors')
var app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json you can choose to just pars raw text as well
app.use(bodyParser.json())
// this will set Access-Control-Allow-Origin * similar for all response headers
app.use(cors())
You can read more about body-parser and cors in their respective repos, if you don't want to use them I would still recommend you use your own middleware in order to reduse future redundancy in your code.
So far this will substitute this part of your code
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
if ( request.method === 'OPTIONS' ) {
response.writeHead(200);
response.end();
return;
}
console.log(request)
let results;
let body = [];
request.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
results = Buffer.concat(body).toString();
// results = JSON.parse(results);
Now your route definition can just be
app.post('/voucher', function (request, response) {
var result = request.body.code // added by body-parser
console.log('#### CHECKING VOUCHER ####', result)
// express 4+ is smart enough to send this as json
response.status(200).send({
success: true,
voucher: {
name: results,
xxx: 10
}
})
})
Client
your client side can then be, assuming $ is jquery's post function
var body = {
code: code
}
$.post('http://localhost:8080/voucher', body).then(function(res) {
console.log(res)
console.log(res.data)
return res.data
})

Node: Basic JSON request

I'm a complete beginner in Node.js and I wanted to consult something I could not figure out.
Even though I've researched extensively I could not find any method to receive JSON request without using a plugin. I will be using it to program a mobile application API. But even though I've incluede parameter request I cannot reach the content by using request.body, or request.data. The request I'm trying to make is;
{
"id":"123"
}
And my failing code is;
var http = require('http');
function onRequest(request, response){
console.log("Request: "+request.data+"\n");
response.writeHead(200, {"Content-Type":"text/plain"});
response.write("Hello, World");
response.end();
}
http.createServer(onRequest).listen(8888);
The problem here is that you're not listening to the request events to let you know that you have data, and then parsing the data. You're assuming that request has request.data.
It should be:
var http = require('http');
function onRequest(request, response){
var data = '';
request.setEncoding('utf8');
// Request received data.
request.on('data', function(chunk) {
data += chunk;
});
// The end of the request was reached. Handle the data now.
request.on('end', function() {
console.log("Request: "+data+"\n");
response.writeHead(200, {"Content-Type":"text/plain"});
response.write("Hello, World");
response.end();
});
}
http.createServer(onRequest).listen(8888);
See this for the documentation for the methods that request contains.