I'm trying to write my first Nodejs server for getting to know Angular/Node and eventually the whole MEAN stack.
My server is running but there's a problem in my code, for some reason when I enter a non existing file, it should redirect to 404, but it doesn't. For some reason the URL gets a double dash;
How would I go about making the redirect to 404 work?
check this image
Here is my code for the server so far.
var http = require('http'),
fs = require('fs'),
path = require('path'),
root = __dirname + '/public/', //magic var
mime = require('mime');
//Server
var server = http.createServer(function (req, res) {
// Check is root is queried
var fileName = '';
var url = req.url;
if (url === '/'){
url = 'index.html'; // redirect when no file specified
}
fileName = root + url;
// check if file exists
fs.exists(fileName, function(exists){
if (exists) {
serveFile(fileName); // yes
} else {
path = root + '404.html'; //no
serveFile(fileName);
}
})
//serve file
function serveFile(requestFile) {
// maak a stream based on events
var stream = fs.createReadStream(requestFile);
res.writeHead(200, {'Content-Type': mime.lookup(requestFile)});
stream.on('data', function (chunk){
res.write(chunk);
});
stream.on('end', function(){
res.end();
});
stream.on('error', function(err){
console.log('error: '+ err);
});
}
});
server.listen(3000); //server start
console.log('Server gestart op http://localhost:3000 ');
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>angular</title>
<link href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="styles/app.css" rel="stylesheet"/>
</head>
<body ng-app class="bg">
<h1>First name?</h1>
<input type="text" placeholder="Type your name" ng-model='firstName'
class="input-lg"/>
<p>
Hi, {{firstName}}
</p>
<img src="https://static.pexels.com/photos/7720/night-animal-dog-pet.jpg" height="100px" width="100px"/>
</body>
<script type="text/javascript" src="https://cdn.jsdelivr.net/angularjs/1.5.5/angular.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/angularjs/1.5.5/angular.min.js"></script>
</html>
Could anyone tell me what's going wrong here?
Thanks in advance!
get rid of the '/' after public:
root = __dirname + '/public'
It is the default behaviour of Node JS. ie. If you request for xxx.com/sample.txt, then the req.url will be "/sample.txt".
https://nodejs.org/api/http.html#http_message_url
So you have consider that in your code, as #Jordan mentioned, remove the "/".
Your redirect also should work fine.
Related
So I just made a HTML page added a script tag with src to a js file and sent the HTML file as response with node js using HTTP module.
But the js file is not working and when I checked the network tab I saw js file is received as text/html file.
Following are the js and html codes.
Server code with node js
const http = require('http') ;
const file = require('fs') ;
const server = http.createServer((req, res) => {
file.readFile('public/login.html', (err, data) => {
if (err) throw err ;
res.writeHead(200, {'Content-Type': 'text/html'}) ;
res.write(data) ;
res.end() ;
})
}) ;
server.listen(5000) ;
front end code : login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<script defer src="js/index.js"></script>
</head>
<body>
<h1>Login</h1>
<form action="" method="post">
<input type="email" name="user" id="user">
<input type="password" name="pass" id="pass">
<button type="submit" name="button" value="login">Login</button>
</form>
</body>
</html>
now when I load the page at localhost:5000, js does not execute and it's received as text/html.
The browser will receive the HTML, see the script tag, and request js/index.js from your server. But your server only sends your HTML file. It doesn't pay any attention to what the browser requested, it just always sends back the HTML. So the script is never sent to the browser, so the browser can't execute it.
Your server code needs to look at req to determine what was requested (looking at url, etc.), and send an appropriate response, rather than always sending back the same content.
Here's a fairly simple example that handles /, /login.html, and /js/index.js paths (making the first two synonyms):
const http = require('http');
const file = require('fs');
const FILENAME_404 = "public/404.html";
const server = http.createServer((req, res) => {
let filename = null;
let contentType = "text/html";
let status = 200;
// What did the browser ask for?
switch (req.url.toLowerCase()) {
case "/":
case "/login.html":
// The login page
filename = "public/login.html";
break;
case "/js/index.js":
// The JavaScript file
filename = "public/js/index.js";
contentType = "text/javascript";
break;
default:
// Something we don't support -- send a 404
filename = FILENAME_404;
status = 404;
break;
}
sendFile(res, filename, contentType, status);
});
function sendFile(res, filename, contentType, status, callback) {
file.readFile(filename, (err, data) => {
if (err) {
// Couldn't read the file, send a 404
if (filename !== FILENAME_404) {
sendFile(res, FILENAME_404, "text/html", 404);
} else {
// Couldn't even find the 404 file, send a minimal plaintext 404
res.writeHead(404, {"Content-Type": "text/plain"});
res.write("The requested resource does not exist on this server.");
res.end();
}
} else {
res.writeHead(status, {"Content-Type": contentType});
res.write(data);
res.end();
}
});
}
server.listen(5000);
Note: This is just an example. If you're going to build anything of any size, you'll want more structure than this. You might look at Express or Koa or others that handle more of the HTTP plumbing, URL routing, etc. for you and have modules available for other things as well.
I'm working on a project where my job is to use Node.js and Socket.io to read a text file (contain 3 real time readings) and got the data in 3 variables, then send them to Socket.io and get them displayed on the website continuously without having to refresh it. I ran my codes, it did not give any errors, but it did not display anything on the website either. So I don't know what is wrong in my code. I need help with passing variables from Node.js to Socket.io and get them displayed on the my web page.
This is my server file:
var http = require('http').createServer(handler); //require http server, and cr$
var fs = require('fs'); //require filesystem module
var io = require('socket.io')(http) //require socket.io module and pass the htt$
http.listen(8080); //listen to port 8080
function handler (req, res) { //create server
fs.readFile(__dirname + '/index.html', function(err, data) { //read file inde$
if (err) {
res.writeHead(404, {'Content-Type': 'text/html'}); //display 404 on error
return res.end("404 Not Found");
}
res.writeHead(200, {'Content-Type': 'text/html'}); //write HTML
res.write(data); //write data from index.html
return res.end();
});
}
io.sockets.on('connection', function (socket) {
setInterval(function(){
var array = fs.readFileSync('report.txt').toString().split("\n");
var volt = (array[0]);
var power = (array[1]);
var temp = (array[2]);
socket.emit('volt',{'volt': volt});
socket.emit('power',{'power': power});
socket.emit('temp',{'temp': temp});
}, 1000);
});
index.html file :
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>
<script>
var socket = io('http://10.117.230.219:8080');
socket.on('volt', function (data) {
$('#volt').text(data.volt);
socket.on('power', function (data) {
$('#power').text(data.power);
socket.on('temp', function (data) {
$('#temp').text(data.temp);
});
</script>
<div id="volt"></div>
<div id="power"></div>
<div id="temp"></div>
</body>
You are missing some tags on your HTML page including HTML and head. You are also missing a closing )} for each socket.on(...) call in your script. This is what it should look like:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>
<script>
var socket = io('http://localhost:8080');
socket.on('volt', function (data) {
$('#volt').text(data.volt);
})
socket.on('power', function (data) {
$('#power').text(data.power);
})
socket.on('temp', function (data) {
$('#temp').text(data.temp);
})
</script>
</head>
<body>
<div id="volt"></div>
<div id="power"></div>
<div id="temp"></div>
</body>
</html>
This should do it.
I am trying to build a Node.js/AngularJS app with Openshift 2. The server is being run successfully and if I go to local adress I get index.html(but blank as it does not load the css), I cant get scripts and links on index.html, I get an error 404 but I dont know why.
Folder structure:
sw [sw master]
pages
index.html
inicio.html
css
inicio.css
js
angular.js
aplicacion.js
app.js
start.js
app.js
const http = require('http'),
fs = require('fs'),
path = require('path'),
contentTypes = require('./utils/content-types'),
sysInfo = require('./utils/sys-info'),
env = process.env;
let server = http.createServer(function (req, res) {
let url = req.url;
if (url == '/') {
url += '/index.html';
}
// IMPORTANT: Your application HAS to respond to GET /health with status 200
// for OpenShift health monitoring
if (url == '/health') {
res.writeHead(200);
res.end();
} else if (url == '/info/gen' || url == '/info/poll') {
res.setHeader('Content-Type', 'application/json');
res.setHeader('Cache-Control', 'no-cache, no-store');
res.end(JSON.stringify(sysInfo[url.slice(6)]()));
} else {
fs.readFile('./pages' + url, function (err, data) {
if (err) {
res.writeHead(404);
res.end('Not found');
} else {
let ext = path.extname(url).slice(1);
if (contentTypes[ext]) {
res.setHeader('Content-Type', contentTypes[ext]);
}
if (ext === 'html') {
res.setHeader('Cache-Control', 'no-cache, no-store');
}
res.end(data);
}
});
}
});
server.listen(env.NODE_PORT || 3000, env.NODE_IP || 'localhost', function () {
console.log(`Application worker ${process.pid} started...`);
});
index.html
<!DOCTYPE html>
<html lang="es" data-ng-app="TFG">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Página principal</title>
<script src="../js/angular.js"></script>
<script src="../js/app.js"></script>
<link href="../css/inicio.css" rel="stylesheet" />
</head>
<body>
<!--CUERPO-->
<div data-ng-view></div>
</body>
</html>
your index file should be at root level as you are providing path in your nodejs file.
Right now your index.html is under "pages" folder.
pages
index.html
inicio.html
I think this will be your tree
sw [sw master]
pages
inicio.html
css
inicio.css
js
angular.js
aplicacion.js
emphasized textindex.html
app.js
start.js
The Node.js script running the server will render html from page folder. This index.html has the css and js linked by relative path from the folder structure but you need to expose that publicly too to get reached by the browser when it tries to get the resources. You will need some code to serve that static content.
In fact, is your own code returning that 404 as the URL that the browser is trying to get the resources (css and js) from your pages folder and they are not found.
fs.readFile('./pages' + url, function (err, data) {
if (err) {
res.writeHead(404);
res.end('Not found');
}
You should include some code that return the css and js files.
This question already has answers here:
How to serve an image using nodejs
(12 answers)
Closed 5 years ago.
Good day ,
I've got a small problem with my NodeJS http server. The server doesn't load the CSS/JS files from folder , only from url and i don't know why. I would appreciate if someone could take some time and give me some tips on what went wrong.
Here is the Server Code :
var http = require("http");
var gs = require("querystring");
var url = require("url");
var fs = require("fs");
var server = http.createServer(function (request, response, err) {
//HTML
if (request.url === "/") {
sendFileContent(response, "HTML/Login.html", "text/html");
console.log("Requested URL : " + request.url + "\n");
}
else if (request.url === "/main") {
sendFileContent(response, "HTML/Main_Home.html", "text/html");
console.log("Requested URL : " + request.url + "\n");
}
// JS / CSS / Other formats
else if (/^\/[a-zA-Z0-9\/]*.js$/.test(request.url.toString(1))) {
sendFileContent(response, request.url.toString().substring(1), "text/javascript");
}
else if (/^\/[a-zA-Z0-9\/]*.css$/.test(request.url.toString()))
{
sendFileContent(response, request.url.toString().substring(1), "text/css");
}
else if (/^\/[a-zA-Z0-9\/]*.json$/.test(request.url.toString()))
{
sendFileContent(response, request.url.toString().substring(1), "application/json");
}
else if (/^\/[a-zA-Z0-9\/]*.ts$/.test(request.url.toString()))
{
sendFileContent(response, request.url.toString().substring(1), "text/javascript");
}
else if (/^\/[a-zA-Z0-9\/]*.png$/.test(request.url.toString()))
{
sendFileContent(response, request.url.toString().substring(1), "image/png");
}
else if (/^\/[a-zA-Z0-9\/]*.jpg$/.test(request.url.toString()))
{
sendFileContent(response, request.url.toString().substring(1), "image/jpeg");
}
else
{
console.log("Requested URL : " + request.url + "\n");
response.end();
}
});
server.listen(1337, function ()
{
require("console-stamp")(console, '[HH:MM:ss]');
console.log("HTTP Server runs on port : 1337");
});
console.log("Server ready....");
And here is the Send file content function :
function sendFileContent(response, fileName, contentType){
fs.readFile(fileName, function (err, data) {
if (err) {
response.writeHead(404);
response.end("Not Found!");
}
else {
response.writeHead(200, { "Content-Type": contentType });
response.end(data);
}
});
};
And this is how i call the files in html
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="../materialize/css/materialize.min.css" media="screen,projection" />
<link type="text/css" rel="stylesheet" href="../CSS/App.css" />
<title></title>
<script type="text/javascript" src="../jquery/jquery-3.2.0.min.js"></script>
<script type="text/javascript" src="../materialize/js/materialize.min.js"> </script>
<script type="text/javascript" src="../Javascript/Main_App.js"></script>
Thank you for your time !
You are trying to implement your own static files server and there so many problems in your implementation even besides those that you're asking about that I think that you need to rethink your approach.
To serve static files it is much easier to use a working solution like express.static - but read below for solutions without Express if you really need it. Example with express.static:
var path = require('path');
var express = require('express');
var app = express();
var dir = path.join(__dirname, 'public');
app.use(express.static(dir));
app.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
See this answer for more options using connect, express, http and net:
How to serve an image using nodejs
In that answer there are examples of doing what you're trying to do here using express.static, Express without express.static, using connect, using http and using net and even the version that uses raw TCP sockets is not as complicated as your code here. You may want to take a look at it and base your code on these examples.
I am trying to display home.html on initial load of localhost:9000, but when I do when the way my current code is, I get the error: friends.js:1 Uncaught SyntaxError: Unexpected token <. I am not sure what this error means. Also, when I do windows.location = localhost:9000/list, in my display.js, the get requests will not send the list.html to the browser, and nothing changes. I tried putting the get request in both server.js and display.js but they both do nothing.
Directory layout
dir main
-server.js
dir subMain
dir display
-display.js
dir routing
-routes.js
dir public
-home.html
-list.html
server.js
var path = require('path');
var express = require('express');
var app = express();
require('./subMain/routing/routes.js')(app, path, express);
app.listen(9000, function(){
console.log('connected on 9000')
})
//app.get('/list', function(request, response){
// response.sendFile(path.join(__dirname + '/..', 'public', 'list.html'));
//});
routes.js
module.exports = function(app, path, express){
app.use(express.static("subMain"))
app.use(express.static(__dirname + "/public"));
app.use(express.static(__dirname + "/routing"));
app.use(express.static(__dirname + "/display"));
app.use(function(request, response, next){
response.sendFile(path.join(__dirname + "/..", "public", "home.html"));
})
app.get('/list', function(request, response){
response.sendFile(path.join(__dirname + '/..', 'public', 'list.html'));
});
}
display.js
$(document).on('click', '#btn', sendSurvery);
function sendSurvery(){
window.location = 'survey.html';
//var myQueryUrl = "http://localhost:9000/survey";
//$.ajax({url: myQueryUrl, method: 'GET', success: function(result){
// location.href = "http://localhost:9000/list"
//}}).done(function(response){
//});
}
home.html
<!DOCTYPE html>
<html>
<head>
<title>Friend Finder Home Page</title>
</head>
<body>
<div class="rowOne">
<!-- <div class="jumbotron col-lg-6"> -->
<h1>Hello, world!</h1>
<p>Click the button</p>
<button id="btn" style="width: 200px;">BUTTON</button>
<!-- </div> -->
</div>
<script src="https://code.jquery.com/jquery.js"></script>
<script type="text/javascript" src="../data/friends.js"></script>
</body>
</html>
You haven't supplied your home.html file, but the issue you're encountering is that your friends.js is not being found by express, and your home.html file is being returned instead. The first character in your home.html file is < and this is why you're getting the error. Check you are referencing the correct path of friends.js and that it is present in your static assets folder.
To confirm my explanation, you can directly access the url you're using to access friends.js and see the contents of home.html returned.