Resolve relative paths in NodeJS/Express - html

I have a web calling several scripts, images, styles, etc., in different folders (inside and outside the main folder):
File tree
- /
- website
- scripts
- data.js
- customJquery.js
- styles
- animate.css
index.html
main.css
back.jpg
- otherFunctions.js
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:400,400i,800,800i">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Faster+One">
<link rel="stylesheet" href="styles/animate.css">
<link rel="stylesheet" href="main.css">
</head>
<body>
<img class="fondo" src="back.jpg">
<div class="content">
<!-- stuff... -->
</div>
<script src='scripts/data.js'></script>
<script src='scripts/customJquery.js'></script>
<script src='../otherFunctions.js'></script> <!-- Here's the conflict... -->
</body>
</html>
All paths are routed ok, except for ../otherFunctions.js. It seems that NodeJS/Express skips de relative part .. and only receives /otherFunctions.js which is handled wrongly.
Here's my server side:
index.js
const express = require('express');
const https = require('https');
const fs = require('fs');
const app = express();
const config = require('./config');
var webId;
var options = {
key: fs.readFileSync(config.paths.certificate.key),
cert: fs.readFileSync(config.paths.certificate.crt),
requestCert: false,
rejectUnauthorized: false
};
app.use(function (req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS, POST, PUT");
res.setHeader("Access-Control-Allow-Headers", "Accept, Access-Control-Allow-Headers, Access-Control-Request-Headers, Access-Control-Request-Method, Authorization, Content-Type, Origin, X-Requested-With");
next();
});
app.get('/favicon.ico', function(req, res) {
res.status(404).send('No favicon found');
});
app.get('/:id', function(req, res, next) {
id = req.params.id;
if (id.search(/\w+\.[A-z]+$/g) < 0) {
webId = id;
res.sendFile('index.html', {root: config.paths.webs + id});
} else {
res.sendFile(id, {root: config.paths.webs});
}
});
app.get('/:folder/:file', function(req, res) {
let folder = req.params.folder;
let file = req.params.file;
res.sendFile(file, {root: config.paths.webs + webId + '/' + folder});
});
app.get('*', (request, response) => {
response.send('GET request not found: ' + request.url);
});
app.use((err, request, response, next) => {
response.status(500).send(err.message);
});
https.createServer(options, app).listen(443, function() {
console.clear();
console.log("NodeJS secure server started at port 443");
});

Unless you have a specific need to serve your static files this way, I'd suggest using the express built-in static file serving.
Regarding the use of '../otherFunctions.js' in your HTML, I'm afraid the browser tries to resolve the path relative to the position of the HTML file itself, so for example, if the HTML file was my.domain.com/foo/bar/index.html, the browser would be looking for my.domain.com/foo/otherFunctions.js. Ideally, all the static files you want to serve to the client should be in one folder that is then used by the express.static(...) call.

Related

Refused to apply style from auth/css when rendering

Problem:
I quite confused to why my render is not loading my css and images from uploads.
When I do not try to log in, every page loads it's images and css applies it's styles..
But when I try to render my page like so:
if(!results.length){
res.status(401).render('home/login', {
message: 'The email or password is incorrect'
});
}
I get this error:
I realized it says ...:3000/auth/css/.. - it's not suppose to load auth?
This is my tree:
Index.js
|
├───controllers
├───helpers
│
├───public
│ ├───css
│ ├───javascript
│ └───uploads
├───routes
│ └───home
└───views
├───home
├───layouts
└───partials
└───home
index.js
const express = require('express');
const path = require('path');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
const app = express();
// Public path
app.use(express.static(path.join(__dirname, './public')));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//Parse URL encoded bodies
app.use(express.urlencoded({ extended: false }));
//Parse JSON bodies as sent by API clients
app.use(express.json());
app.use(cookieParser());
// View engine
app.engine('handlebars', exphbs({defaultLayout: 'home-index'}));
app.set('view engine', 'handlebars');
// Routing
app.use('/', require('./routes/home/page_routes'));
app.use('/auth', require('./routes/auth'));
app.listen(3000, () => {
console.log('Listening');
});
views/layouts/home-index.handlebars
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="css/home.css">
<title></title>
</head>
<body>
{{> home/home-nav}}
{{{body}}}
</body>
</html>
routes/auth.js
const { db } = require('./db');
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
var { promisify } = require('util');
// Login
exports.login = async function(req, res) {
try {
var {email, password} = req.body;
if(!email || !password) {
return res.status(400).render('home/login', {
message: 'Please provide an email and password' ///////////////// This is the problem
});
}
db.query('select * from users_website where email = ?', [email], async function(error, results){
console.log(results)
if(!results.length){
res.status(401).render('home/login', {
message: 'The email or password is incorrect' ///////////////// This is the problem
});
}
else{
var id = results[0].id;
var token = jwt.sign({ id }, 'SuperSecretPassword9981998', {
expiresIn: '90d'
});
console.log("The token is: " + token);
var cookieOptions = {
expires: new Date(
Date.now() + 90 * 24 * 60 * 60 * 1000
),
httpOnly: true
}
res.cookie('jwt', token, cookieOptions);
res.status(200).redirect("/");
}
});
} catch (e) {
console.log(e);
}
}
routes/home/page_routes
const express = require('express');
const router = express.Router();
const auth_controller = require('../../controllers/auth');
// Home router
router.get('/', auth_controller.isLoggedIn, (req, res) => {
res.render('home/index');
});
// Login
router.get('/login', (req, res) => {
res.render('home/login');
});
module.exports = router;
Question
How do I get rid of the error - when trying to render the page?
The reason for this is that you are loading assets using relative URLs in your handlebars file, which means that the assets are loaded relative to the page's URL, which, in your case, is :3000/auth. To fix this, use an absolute URL instead.
Like this:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<!-- Notice the leading slash. -->
<link rel="stylesheet" href="/css/home.css">
<title></title>
</head>
<body>
{{> home/home-nav}}
{{{body}}}
</body>
</html>

How to create node.js html server with css

Im trying to create simple node.js server for html using http and express
It's working, but css don't showing
Here is code of my server
const express = require("express");
const app = express();
app.use(express.static("css"));
var router = express.Router()
app.use('/',router)
router.get("/", (req, res) => {
res.sendFile(__dirname + "/index.htm")
})
app.listen(8080)
And code of my server, what created using http
const http = require("http")
const port = 8080
const fs = require('fs')
const server = http.createServer(function(req,res) {
fs.readFile('./index.html', (error, data) => {
if(error) {
res.writeHead("404")
res.write("Error. File not found.")
} else {
res.use
res.write(data)
}
res.end();
})
})
server.listen(port, function(error) {
if(error) {
console.log(error)
} else {
console.log("server is listening on port " + port)
}
})
all my html code
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Domodinak</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<p>Hello world</p>
</body>
</html>
also css
body {
background-color: deeppink;
}
if you know how to help me, please help :)
Make sure that you're addressing css folder correctly. It depends on your project folder structure. It is suggested to save your static files in a folder called public and then save your files in separated folder like js and css. For example, i assume that you have a src folder which is your directory for express server file, another folder alongside the src folder, you have a public folder with css subfolder.
Put your stylesheet file in css subfolder, and html file in just public folder and then change your code to this:
const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(path.join(__dirname, "../public")));
// var router = express.Router()
// app.use('/',router)
// router.get("/", (req, res) => {
// res.sendFile(__dirname + "/index.htm")
// })
app.listen(8080)
Your project structure should looks like this:
|-public -| css -| style.css
index.html
|-src -| app.js
Run the server file then check your browser with just localhost:8080. It serves index.html from static directory which you passed to express earlier.

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

Uncaught SyntaxError: Unexpected token <, Angular 6 trying to connect to node server.js

I am using Angular6, trying to serve json data from a google map API to make ajax calls to Node.js with MongoDB, I have a form for placing markers on a google map using the api, I am trying to set up node js to take in the json data so that it is not being stored on the local storage, I have being following tutorials trying to set up Node.js to work with express and to store the places.
Using express: "^4.16.3", mongodb: "^3.1.1",
I have created the dist folder with all of the relevant files and I have also created my server folder with route folder and api.js, also I have my server.js, I think that I have all in place but I keep getting this error in my console when I run it on the local host 3000,
this is the error that is showing up in my google chrome console
When I run http://localhost:3000/api it displays that the text 'api works'
This is my Server.js
// Get dependencies
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
// Get our API routes
const api = require('./server/routes/api');
const app = express();
// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));
// Set our api routes
app.use('/api', api);
// Catch all other routes and return the index file
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/mapit/index.html'));
});
/**
* Get port from environment and store in Express.
*/
const port = process.env.PORT || '3000';
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port, () => console.log(`API running on localhost:${port}`));
This is my api.js
const express = require('express');
const router = express.Router();
/* GET api listing. */
router.get('/', (req, res) => {
res.send('api works');
});
module.exports = router;
This is my index.html in my dist folder
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Mapit</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://bootswatch.com/4/simplex/bootstrap.min.css">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
<script type="text/javascript" src="runtime.js">
</script><script type="text/javascript" src="polyfills.js"></script>
<script type="text/javascript" src="styles.js"></script>
<script type="text/javascript" src="vendor.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
I think you have the following problem, you don't call next on your middleware and thus the HTML file cannot be send. You also try to call res.send() twice which you shouldn't do, express can only send one response. I suggest you change your api the following:
router.get('/', (req, res, next) => {
console.log('api works');
next();
});
Now the api works will logged in the terminal (nodejs) and not the browser console and the HTML should be send succesful.
Hopefully helps you!
Try app.use(express.static(path.join(__dirname, 'dist/mapit')));
Difference is using 'dist/mapit' instead of only 'dist'.
Where have you placed your server.js file? I was seeing the same issue when I had my server.js within the DIST folder.
I moved the server.js file up one level so it is in the parent directory of the DIST folder and my site files css/js etc all loaded as expected.

How to read image from HTML file with NodeJS?

I want to read an HTML file.
My HTML content:
<html>
<hear>
<title>Learn NodeJS</title>
</head>
<body>
<center>
<h1>Learn NodeJS with Khuong Pham</h1>
<img width="400" src="/nodejs.png" />
</center>
</body>
</html>
I've tried:
const http = require('http')
const fs = require('fs')
const express = require('express')
const app = express()
const folderPath = __dirname + '/public_files'
app.use(express.static(folderPath))
http.createServer(function(request, response) {
var filePath = folderPath + '/index.html'
console.log(filePath)
fs.access(filePath, fs.F_OK | fs.R_OK, function(err) {
if (err) {
response.writeHead(404, { 'Content-Type' : 'text/html' })
response.end('<h1>File not found</h1>')
} else {
fs.readFile(filePath, function(err, contentFile){
if (!err) {
response.writeHead(200, { 'Content-Type' : 'text/html' })
response.end(contentFile)
} else {
response.writeHead(500, { 'Content-Type' : 'text/html' })
response.end('<h1>Can not read this content</h1>')
}
})
}
})
}).listen(3500)
But when I access http://localhost:3500/, it says:
You are mixing two methods here. Firstly you are trying to use express, but later you are starting your own server using http.createServer Instead you should use express to do so.
Your js should be something similar to below. Have not tested below code. Edit it approiately. This is just to show the idea.
const http = require('http')
const fs = require('fs')
const express = require('express')
const app = express()
const folderPath = __dirname + '/public_files'
//mount your static paths
// renders your image and index.html
app.use(express.static(folderPath))
// renders your index.html
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
//mount your other paths
// in this case render 404.
app.get("*",function (req, res) {
res.status(404).send(''<h1>File not found</h1>'');
});
//start the server.
app.listen(3500, function () {
console.log('Example app listening on port 3500!');
});