How does Node.js render views? - node.js

In a basic Node.js application with a single app.js file and one index.html document where in app.js the following is specified, then firing up a server and visiting localhost:8080 works just fine:
server = http.createServer( function(req, res) {
fs.readFile('index.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
fs.readFile('new.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
});
server.listen(8080);
However, when duplicating index.html to another file like new.html and editing certain content, then adding an link into index.html linking to the new page, clicking on the link will render the same content as in index.html. In fact, linking to any non-existent html page will append the subsequent page to the URL but keep showing index.html's contents.
Following a suggestion of rewriting the fs.readFile line to be:
fs.readFile(req.url, function(err, page) { ...
Then going to localhost:8080 loads new.html's contents for some reason I don't understand. How should one render out these views?

Following on the other answers given and also recommending express. But first, the short answer to the question "how does node.js render views?" is: it doesn't.
When you build a node application you are building a small web server, using the minimal building blocks node gives you like http.createServer(). It's up to you to write the logic to choose what to send in response to a request.
Or you can use an existing framework like Express. Here is the solution using express:
Install express:
npm install express
Then, in your app.js:
var express = require('express');
var app = express.createServer();
app.get('/index.html', function(req,res) {
res.render('index.html');
});
app.get('/new.html', function(req,res) {
res.render('new.html');
});
app.listen(8080)
You can also use EJS or Jade as the template language by adding this before the createServer line:
app.set('view engine', 'ejs');
or:
app.set('view engine', 'jade');

Because you need to have conditions on your request access url (req.url).
Right now it closes the response on your first res.end() regardless of your url, and never reach the rest of your code (well it does but the response already fired before so it has no effect).
try this:
server = http.createServer( function(req, res) {
if (req.url == '/index.html') { //will be executed only on index.html
fs.readFile('index.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
}
if (req.url == '/new.html') { //will be executed only for new.html
fs.readFile('new.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
}
});
server.listen(8080);

Related

nodejs + express + swig: how do I check the request before rendering?

To be honest, I don't really know how nodejs, express, and swig work.
I have this code that seems to serve up all my html pages
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('views', __dirname+'/html');
I'd like to be able to examine the request before returning the html file. Specifically, I want to check if the user is using an older version of IE and redirect them to another page instead.
Now, I can examine the request and redirect for specific pages like so
app.get('/veryspecificpage.html', function(req, res) {
if( isBadBrowser(req) ) {
res.writeHead(302, {
'Location': 'browserError.html'
});
res.end();
} else {
res.render('veryspecificpage', {});
});
})
But I don't want to have to specify this for every single .html page. How do I intercept the request and do this for all html pages?
Log each request
Sample node web server. Simply log each request to the server like this...
var http = require('http');
http.createServer(function (req, res) {
console.log(req); // <--- LOGS EACH REQUEST
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
You should use middleware to check every request.
// gets executed for every request to the app
app.use(function (req, res, next) {
// check for browser here and redirect if necessary, if not, next() will continue to other middleware/route.
next();
});
Make sure you place it before any route. You can learn more about it by going to this page.

Unable to serve image (png) with node.js and express

I've studied similar questions on SO but haven't found a solution to my problem... I've set up an express route to serve images but I can't get it to return an image from where it's stored. Notice I've included a statement to allow requests from any origin. What happens is that when I make a request to http://localhost:8080/images/x10.png the response I get is an empty image element with src="http://localhost:8080/images/x10.png instead of from http://ubuntubox.dev/images/x10.png, which is where the image is actually located and is the path I'm ultimately passing to the request method. What am I missing? Thanks.
app.get('/images/*', function(req, res, path){
var imagePath = req.url,
url = 'http://ubuntubox.dev' + imagePath;
request(url, function(error, response, img) {
if(!error && response.statusCode === 200) {
res.header('Access-Control-Allow-Origin', '*');
res.writeHead(200, {'Content-Type': 'image/png' });
res.end(img, 'binary');
} else if(response.statusCode === 404) {
res.status(404);
res.type('txt').send('oops');
}
});
}).listen(8080, '127.0.0.1');
I don't know if you still have this problem, but..
The solution for your problem is just putting a .pipe(res) and it will send the file to the response
app.get('/images/*', function(req, res, path){
var imagePath = req.url,
url = 'http://ubuntubox.dev' + imagePath;
request(url).pipe(res);
}).listen(8080, '127.0.0.1');
If you want to serve images and other assets in a way that makes sense and doesn't require you to write a million routes, try this:
Create a new folder "public" and move all of your assets into it.
Open server.js and add the following line:
app.use(express.static('public'))
Your assets should now be available like so:
http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html
Soure: https://expressjs.com/en/starter/static-files.html
Just figured this out for myself in express 4
app.get('/images/img1.png', function(req, res){
res.sendFile('/Absolute/path/to/the/file/images/img1.png');
});
user2879041 has already answered what he found useful, still I would think of another way for serving images, (where I shall not write a route for each file manually and the send the file to the browser).
As you are already using express, just server tyhe static images directly, you have already got that in express.static
app.use(express.static('/Absolute/path/to/the/file/images/img1.png'));
benefit of using express.static is that you would just keep adding the images inside the folder you want to be static and express will serve the images for you(no need to add any code).
I am not sure if it's the same case or not.
But here is my answer:
var path = require('path');
var express = require('express');
var app = express();
var dir = path.join(__dirname, 'public');
app.use('/public', express.static(dir));
app.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
Notice this line:
app.use('/public', express.static(dir));
You need to add the path again with the app.use method
I don't get the idea of adding this part, but it was the only way to make it works.
and without it keeps responding 'Error' and I can not access this file.
hopefully, I could help you.

Node.js + Serve Static Files with RESTIFY

I have a multi-level collection of .html, .js, .png, .css, etc files in a site. A peek at my site hiearchy looks like the following:
index.html
child1
index.html
page1.html
page2.html
...
child2
grandchild1
index.html
grandchild2
index.html
index.html
page1.html
page2.html
resources
css
myTheme.css
img
logo.png
profile.png
js
jquery.js
...
...
I am migrating this to run under Node.js. I have been told I MUST use RESTIFY. Currently, I've written the following for my server:
var restify = require('restify');
var fs = require('fs');
var mime = require('mime');
var server = restify.createServer({
name: 'Demo',
version: '1.0.0'
});
server.use(restify.acceptParser(server.acceptable));
server.use(restify.queryParser());
server.use(restify.bodyParser());
server.get('/', loadStaticFile);
server.get('/echo/:name', function (req, res, next) {
res.send(req.params);
return next();
});
server.listen(2000, function () {
console.log('Server Started');
});
function loadStaticFile(req, res, next) {
var filePath = __dirname + getFileName(req);
console.log("Returning " + filePath);
fs.readFile(filePath, function(err, data) {
if (err) {
res.writeHead(500);
res.end("");
next(err);
return;
}
res.contentType = mime.lookup(filename);
res.writeHead(200);
res.end(data);
return next();
});
}
function getFileName(req) {
var filename = "";
if (req.url.indexOf("/") == (req.url.length-1)) {
filename = req.url + "index.html";
} else {
console.log("What Now?");
}
return filename;
}
With this code, I can successfully load index.html. However, my index.html file references some JavaScript, image files, and style sheets. I can see via Fiddler that that these files are being requested. However, in my node.js console window, I never see "Returing [js|css|png filename]". Its like my node.js web server returns index.html and that's it.
What am I doing wrong?
The latest versions of restify has builtin middleware serveStatic() middleware that will do this for you.
from a http://mcavage.me/node-restify/#Server-API
server.get(/\/docs\/public\/?.*/, restify.serveStatic({
directory: './public'
}));
for more detailed example:
http://mushfiq.me/2013/11/02/serving-static-files-using-restify/
Do any of your served files contain relative paths (say ../abc.js)?
You have to use path.resolve() to get the real path for fs.readFile().
Anyway there are a lot of pitfalls in serving files:
invalid url (400)
file not found (404)
escape sequence (url encoding)
fs.read() read files into memory (by #robertklep)
etc
You can use existing static file serving middleware.
I've been using Ecstatic, AFAIK it handles those issues properly.
Try
server.use(ecstatic({ root: __dirname + '/' }));
If that fails you can refer to this to stack Restify on top of Connect/Express.

Node.js catch-all route with redirect always renders index page with Angular regardless of url

Essentially when I use a catch-all route and use res.redirect('/') regardless of the url I enter it will always render the index/home page (ie Angular does not seem to 'see' the full url) however if I place res.render('index') in the catch-all route everything works fine. I don't want repeat code and redirecting to '/' should work, I have probably made a stupid mistake somewhere here and any help would be much appreciated!
Angular routing:
app.config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider
.when('/',
{
templateUrl: 'partials/home.jade'
})
.when('/about',
{
templateUrl: 'partials/about.jade'
})
.otherwise( {redirectTo: '/'});
});
This will correctly render the about page when entering site-address/about:
app.get('/', function (req, res) {
res.render('index');
});
app.get('/partials/:name', function (req, res) {
res.render('partials/' + req.params.name);
});
app.get('*', function (req, res) {
res.render('index');
});
This will always just show the index page:
app.get('/', function (req, res) {
res.render('index');
});
app.get('/partials/:name', function (req, res) {
res.render('partials/' + req.params.name);
});
app.get('*', function (req, res) {
res.redirect('/');
});
Configuration if it helps:
// Configuration
app.configure(function () {
app.set('port', process.env.PORT || 1337);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(path.join(__dirname, 'public')));
app.use(app.router);
});
This is by design.
When you use res.redirect('/'), Node/Express is sending an HTTP redirect, which will change the URL in the browser, thus when your index template is rendered, and when the angular code is run, the URL is /, regardless of what the user entered (the whole point of the redirect).
When you omit the redirect and just send the template as a response, NodeJs responds with an HTTP 200 (success) along with HTML content. Since the URL didn't change, when your application runs, the angular routing properly routes.
EDIT TO ADD: Address Comment
Rather than have two routes render the same template, I would get rid of the / route all together, and just have the catch-all render the index template, which will then turn control over to the Angular router.
Otherwise, I would consider splitting your routes conceptually: All your application routes are specifically sent to angular router, and you render static routes via nodejs, and use your catch all to render a more appropriate page for a missing or unknown resource (more helpful for your users).
You can use regex-like languages to specify a single handler:
app.get('/()|(about)|(contact)/',function(req,res) {/* handle */});
For folder structure:
root
-web.js
-dist/index.html
-dist/rest of the page
Just paste the following snippet to your web.js
nodeApp.use('/', express.static(__dirname + '/dist'));
nodeApp.get('/[^\.]+$', function(req, res){
res.set('Content-Type', 'text/html')
.sendfile(__dirname + '/dist/index.html');
});
I have a problem where when I use the catch-all routing, all of my static assets (stylesheets, javascript files etc) don't load:
app.use(app.router);
app.use(express.static(path.join(__dirname, frontend.app)));
// when this is removed, I can load static assets just fine
app.get('*', function(req, res){
res.render('main');
});
When the app.get('*', ...) part is removed, I can load the static assets just fine (i.e. I can type in 'examplejavascript.js' and see the javascript file. When it is there however, express catches the assets.
$locationProvider.html5Mode(true);
are you sure your requests are hitting the nodejs server. using this means, angularjs will try to search for urlmapping inside browser.
try by commenting
$locationProvider.html5Mode(true);

How to show the node.js output in HTMLPage

I am using webmatrix and building node.js application.
In that i want to pass the value from the node.js to the HTMLPage in the project.
var http = require('http');
var URL = require('url');
http.createServer(function (req, res)
{
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('Hi man');
}).listen(process.env.PORT || 8080);
With that code i tried it gives a page with hi man.Its obvious.But i want this to be rendered in the html page i am having in the project.
How to achieve tat.
Please give some suggestion on this..
First I recommend you use Expressjs, which is a framework for Nodejs.
Then I recommend you use EJS, an engine template for Nodejs.
When integreses all, you can use code similar to:
...
app.set('views', __dirname + '/views');
app.register('.html', require('ejs'));
app.set('view engine', 'html');
app.use(express.static(__dirname + '/public'));
app.use(express.favicon(__dirname + '/public/img/favicon.ico', { maxAge: 2592000000 }));
app.use(expressValidator);
...
And
...
app.get('/test', function(req, res){
res.render('test', {msg: "Hello World"});
});
...
Finally in your file views/test.html:
...
<div><%- msg %></div>
...
I hope it helps somewhat.
Additionally review:
http://utahjs.com/2010/09/25/nodejs-express-and-ejs-templates/
Render ejs file in node.js
Node.js - EJS example
Greetings.
Sounds like you want to request your nodejs server using AJAX and inject the server's response into an HTML element.
Check out: http://api.jquery.com/jQuery.getJSON/
Here's an example using jQuery to connect and retrieve the server response from node running on port 8080 of different host, and insert that into an HTML element.
node:
var http = require('http');
var url = require('url');
http.createServer(function (req, res)
{
//parse the url and query string from the request
var url_parts = url.parse(req.url, true);
//if the callback query parameter is set, we return the string (or object)
if(url_parts.query.callback){
var str = "Hi man";
res.writeHead(200, {'Content-Type':'text/html'});
res.end(url_parsed.query.callback+'("'+str+'")');
//if it's not set, let's return a 404 error
}else{
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('404 Error');
}
}).listen(process.env.PORT || 8080);
index.html
<div id="my-div"></div>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function(){
//getJSON and the callback paramater make us cross-domain capable.
$.getJSON('http://myotherhost.com:8080/?callback=?', function(data){
$("#my-div").html(data);
});
});
</script>

Resources