I have a node.js application and I am stuck getting an error message when I try to load the homepage. I will do my best at laying out my architecture below. It goes index.js --> server.js --> router.js --> requestHandlers.js
I am using a combination of express (www.expressjs.com) and nodebeginner.org. Sorry for the long question.. just wanted to get as much information down as possible.
index.js (creates handle object that contains pathname/requesthandler information, calls function to start server) I start with router.route here and pass it along each step
var server = require("./server");
var router = require('./router');
var requestHandlers = require('./requestHandlers');
// Routes
var handle = {}
handle['/'] = requestHandlers.home;
server.start(router.route, handle)
server.js (starts the server, THIS IS WHERE I WANT TO CONFIGURE THE SERVER, gets a the pathname from the URL, and passes it on to the route module)
var http = require("http");
var url = require('url');
var express = require('express');
function start (route, handle) {
var onRequest = function(request, res) {
var pathname = url.parse(request.url).pathname;
console.log("request for " + pathname + " recieved.");
route(handle, pathname, res);
}
var app = express.createServer(onRequest).listen(8888);
if (app.configure) {
console.log('app exists'); //logging correctly
}
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env); //logs correct with 8888 and development
}
exports.start = start;
router.js (the function route passed from index --> server which calls the route function in router.js, calls the requestHandler that matches the pathname in handle object)
function route (handle, pathname, res) {
console.log("About to route a request for" + pathname); //About to route a request for/stylesheets/style.css SEE BELOW******* this is the error
if (typeof handle[pathname] === 'function') {
handle[pathname] (res);
}
else {
console.log('no request handler found for' + pathname);
}
}
exports.route = route;
requestHandler.js (interacts with the res/req objects, functions are mapped to certain pathnames, only called when those pathnames are requested thanks to the router)
var home = function(res){
res.render('index', { title: 'WWYB?' });
console.log('homepage rendered'); //correctly logs for pathname = '/'
//click();
};
exports.home = home;
***when i go to request localhost:8888 it tries to make a bunch of requests. first it requests "/" correctly but then keeps going through logging everything saying "About to route a request for/stylesheets/style.css" Eventually the page loads with no css. The pathname as indicated in my layout.jade file is exactly that '/stylesheets/style.css'.
Why is the pathname ever evaluating to /stylesheets/style.css? I think node is doing something in the background and I dont fully understand it.
Let me know if you need more info. Thanks!
Like #TJHolowaychuk commented you really should check the manual, and follow a bunch of tutorials. Anyway, I'll try to help you a bit.
The is a very basic explanation. Express allows you to use sub applications, so you can have different part of you application in different files. It has it's own router too. If you need to do something with the request and/or the response before the route is processed, you can create a middleware. If you want you configurations in a different module, then return a function in it.
So an example of server.js :
var $express = require('express'),
app = module.exports = $express.createServer(),
subapp = require('./subapp'),
configure = require('./configure');
// Each of our own configure returns a function that will be
// called by app.configure
app.configure(configure.all(app));
app.configure('development', configure.devel(app));
app.configure('production', configure.prod(app));
// Use our sub application
app.use(subapp);
// Now listen
app.listen(3030)
subapp.js :
var $express = require('express'),
subapp = module.exports = $express.createServer();
// Add a handler for GET / to our sub-application
subapp.get('/', function (req, res) {
res.end('Hello world!');
});
Finally configure.js :
var $express = require('express');
exports.all = function (app) {
return function () {
// Global configurations
app.use($express.bodyParser());
app.use($express.methodOverride());
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use($express.static(__dirname + '/public'));
//...
// If you want to do something with/on the request/response
// you can create a middleware
app.use(function (req, res, next) {
console.log('caught request %s %s', req.method, req.path);
// Don't forget the callback
next();
});
};
};
exports.devel = function (app) {
return function () {
// Development configurations
};
};
//...
Go to localhost:3030 with your favorite browser, it displays "Hello world!", this is our request handler. If you look at the terminal, you'll see "caught request GET /", this is our middleware.
Your stylesheets, client-side javascripts, etc. should be in /public. app.use(express.static(__dirname + '/public')) will serve these.
Let's say you have /public/stylesheets/all.css, then in your jade template you can include it like this link(rel='stylesheet', href='/public/stylesheets/all.css')
Now, you'll have to experiment and learn more about node and express before even thinking to deploy something to production, these websites may help you:
howtonode
nodetuts
Hope this tiny-micro-tut helps you.
woah this is pretty confusing, you might want to start with the app express(1) can generate for you
Related
So, its been a hot minute since I've used node, and i can not for the life of me, understand why this isn't working.
const body_parser = require("body-parser");
var express = require("express");
var app = express();
app.use("/", express.static(__dirname + "/Contents/"));
app.get("/", function(req, res) {
//Why wont this log to my terminal when a user visits the site?
console.log("log it pleaseeeeeeeeee");
});
app.listen(5004, () => {
console.log("server up and listening on port 5004");
});
I'm trying to log "Log it Pleaseeeee" every time a user visits the site, into the terminal where my nodejs app is running. Why wont this work?
You can't have 2 seperate handlers for an endpoint, in your case "/"
To achieve what you want, you must provide a middleware function.
express will know based on the type of the second argument what to do. middleware functions expect 3 arguments; the last being a callback so it knows when you are ready.
You should change your code by moving your get function into your app.use('/', ...) function and including the callback parameter as follows:
const body_parser = require("body-parser");
var express = require("express");
var app = express();
app.use("/", function(req, res, callback) {
console.log("log it pleaseeeeeeeeee");
callback()
}, express.static(__dirname + "/Contents/"));
/** GET RID OF THIS
app.get("/", function(req, res) {
//Why wont this log to my terminal when a user visits the site?
console.log("log it pleaseeeeeeeeee");
});
*/
app.listen(5004, () => {
console.log("server up and listening on port 5004");
});
I have the following code from a node.js server that uses the express framework:
var fs = require('fs')
express = require('express')
handlebars = require('express-handlebars');
var helpers = require('./lib/helpers');
var app = express();
app.use(function(req, res, next){
var pathUrl = req.path;
if(pathUrl !== '/')
res.download(__dirname + '/' + 'download.png', 'download.png', function(err){
console.log(err);
});
next();
});
app.get('/', function(req, res){
res.send('<a href=' + '/download.png' + '>' + 'download' + '</a>');
});
app.listen(3001);
When run, this code creates the following error:
{ Error: Request aborted
at onaborted (/home/js/webdev/fs/node_modules/express/lib/response.js:1021:15)
at Immediate._onImmediate (/home/js/webdev/fs/node_modules/express/lib/response.js:1063:9)
at runCallback (timers.js:696:18)
at tryOnImmediate (timers.js:667:5)
at processImmediate (timers.js:649:5) code: 'ECONNABORTED' }
If res.download() changes on to res.send('Helo'), it works.
Why does res.download() not work?
Thanks.
You're not allowing res.download() to finish
The Error: Request aborted means that express hasn't had a chance to finish sending what it needs to send.
When you call res.download(), it's equivalent to performing res.send() except making sure it has adequate headers for the browser to know it's a file download, instead of something to display in the browser. This function call is asynchronous, meaning that it will continue running in the background and then run the next line of code, which in this case, is next().
next() gets called, which then tells express to continue looking for routes that match, or, in this case, there are no more routes that match and express will terminate the connection. This is not what you want, as you're still trying to finish the file download. You don't need express tell you when you're done, you say when you're done.
How to fix it?
Very simply, just make sure that express cannot continue to the next route in the middleware if the route isn't /. Add an else clause to your conditional:
app.use(function(req, res, next){
var pathUrl = req.path;
if(pathUrl !== '/') {
res.download(__dirname + '/' + 'download.png', 'download.png', function(err){
console.log(err);
});
} else {
next();
}
});
Footnote
This is not the easiest way to accomplish what you're trying to do here. You can use wildcard route matching (*) to make this much simpler. I've given your code a little tidy up that includes some of these features.
const path = require("path");
const express = require("express");
const app = express();
app.get("/", (req, res) => res.send(`download`));
app.get("*", (req, res) => {
res.download(path.join(__dirname, "./download.png"), "download.png", err => {
if (err) console.log(err);
});
});
app.listen(3001);
(req, res) => {} is a cleaner way of writing function(req, res) {}
the path module should be used as it can handle multiple OS's
the * wildcard route will match anything, and should usually always go last
we now check to see if there is an err before we console.log() it
Trying to set up a basic Express server with a basic pug template.
Can you please tell me what I'm doing wrong here?
'use strict';
//Require Express
var express = require('express');
var app = express();
//Require Pug
var pug = require('pug');
//Require Twitter
var Twitter = require('twitter');
//Set view engine to serve middleware
app.set('view engine', 'pug');
//Set where to look for templates
app.set('views', __dirname + '/templates');
//Set up style sheets
app.use('/static', express.static(__dirname + '/public'));
//Access keys to access twitter account
var config = {
"consumerKey": "",
"consumerSecret": "",
"accessToken": "",
"accessTokenSecret": ""
};
//instantiate twitter client
var client = new Twitter(config);
//Log whether
var error = function (err, response, body) {
console.log('ERROR [%s]', err);
};
var success = function (data) {
console.log('Data [%s]', data);
};
//Set up server on Port 3000
app.listen(3000, function() {
console.log("The frontend server is running on port 3000!");
});
//Render when appropriate
//Tell app to render template
app.get('/'), function(req, res){
res.render('index', {title: 'Hey', message: 'Hello there!'});
}
I'm getting back The frontend server is running on port 3000! in the console.
What am I missing?
I'd really appreciate any help please
You're calling app.get() wrong. You're doing
app.get('/'), function(req, res){
...
Which is two statements separated by the comma operator. The correct syntax is to pass the function as the second argument:
app.get('/', function(req, res){
...
});
I have this AngularJS SPA with ui-router which works perfectly. It uses parse.com as the backend, and I have it working on a regular Apache server.
Now I want to move it to a node.js server-app, and I want node.js to handle all the CRUDs for parse.com.
I set up a nice little node.js app to act as server, and it works.
My question is: How do I handle requests between my node.js server-app and my AngularJS SPA?
I've included my server.js file, in case anyone can use it.
// set up =====================================================================================================
var express = require('express'),
path = require('path'),
morgan = require('morgan'),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
routes = require('routes'),
keys = require('./config/keys'),
port = 80;
var app = express();
var Parse = require('parse/node').Parse;
// view engine setup ==========================================================================================
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// configuration ==============================================================================================
app.use(require('prerender-node').set('prerenderToken', keys.prerender));
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({'extended':'true'})); // parse application/x-www-form-urlencoded
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());
app.use(express.static(path.join(__dirname, 'public_html')));
Parse.initialize(keys.app, keys.js);
// routing ====================================================================================================
app.use(function(req, res) {
"use strict";
// use res.sendfile, as it streams instead of reading the file into memory. ===============================
res.sendfile(__dirname + '/public_html/index.html');
});
app.use('/', routes);
// catch 404 and forward to error handler =====================================================================
app.use(function(req, res, next) {
"use strict";
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// listen (start app with node server.js) =====================================================================
app.listen(port);
console.log("App listening on port %d", port);
File structure:
- public_html/ <-- the angularjs app -->
- node_modules/ <-- installed modules for node -->
- config/
- keys.js
- server.js
- package.json
The current setup
So, currently, I would deal with parse.com data in my (angularjs) app controller - and some of it in parse's cloud-code.
Now, I want to move all parse.com dealings to my node.js server-app, so that my angularjs "calls" the node.js server-app, which in turn "calls" parse.com for the data I need, and then return it to the angularjs app so I can update my views (with the new data from parse.com).
Example of what I want
parse.com <--> node.js server-app <--> angularjs SPA (views)
A simple thing I do in my controller is something like
var Profile = Parse.Object.extend('Profile');
var query = new Parse.Query(Profile);
query.equalTo('objectId', $stateParams.authorPermaLink);
query.find().then(function(results){
var object = results[0];
$scope.authorObj = results[0];
$scope.template.pageName = object.get('screenname');
$scope.template.pageAuthor = object.get('screenname');
$scope.template.pagePublished = object.createdAt;
$scope.template.pageLastEdit = object.updatedAt;
$scope.$apply();
}, function(error){
// error-handling
console.log("Error: " + error.code + " " + error.message);
});
Now, moving this snippet of code to node.js is simple because I can use the parse.com SDK in node.js directly. But how do I get the angularjs app to communicate with the node.js server-app?
Okay, so I managed to brain my way out of this.
The solution is to make routes that will handle http-requests from my angularjs app.
routes.js (node):
app.get('/api/article/:permalink', function(req, res) {
blog.getArticle(req.params.permalink, function(data) {
res.json(data);
});
});
// everything else
app.use(function(req, res) {
// use res.sendfile, as it streams instead of reading the file into memory.
res.sendfile('./public_html/index.html');
});
Then create a model with the blog object and methods, which are called above.
model.js (also node):
module.exports = {
getArticle : function(permalink, callback) {
"use strict";
var Article = Parse.Object.extend('Article');
var query = new Parse.Query(Article);
query.include('category');
query.include('profile');
query.equalTo('permalink', permalink);
query.find().then(function(results) {
var result = results[0];
var object = {
title: result.get('title'),
screenname: result.get('profile').get('screenname'),
profileID: result.get('profile').id,
content: result.get('content'),
publishedAt: result.get('publishedAt'),
updatedAt: result.updatedAt,
categoryName: result.get('category').get('categoryName'),
categoryPermaLink: result.get('category').get('categoryPermaLink'),
articleID: result.id
};
callback(object);
}, function(error) {
callback({error: error});
});
}
};
And then finally in mu angularjs app, simply make a http-request (get in this example but the other rest verbs all work as well).
controller.js (angularjs):
$http.get('/api/article/' + $stateParams.articlePermaLink
).then(function successCallback(response) {
response = response.data;
$scope.articleTitle = response.title;
$scope.template.pageName = response.title;
$scope.articleAuthor = response.screenname;
$scope.template.pageAuthor = response.screenname;
$scope.profilePermaLink = response.profileID;
$scope.articleContent = response.content;
$scope.publishDate = response.publishedAt;
$scope.template.pagePublished = response.publishedAt;
$scope.template.pageLastEdit = response.updatedAt;
$scope.category = response.categoryName;
$scope.categoryPermaLink = response.categoryPermaLink;
$scope.currentArticle = response.articleID;
console.log(response.commentObj);
}, function errorCallback(response) {
console.log("Error: " + response.code + " " + response.message);
});
The callbacks are the magic!
I´m new in node and express and I do a little app but it doesn´t work. I do post in page 1, and the app doesn´t show page 2. The structure and code is:
/
/controller/controllers.js
/node_modules/express
/jade
/mongoose
/view/index1.jade
/index2.jade
/layout.jade
app.js
package.json
The app.js
/* server */
var express = require('express')
, routes = require('./routes')
, fs = require('fs');
//Create server
var app = express.createServer();
//Use controller
var controllers_path = __dirname + '/controllers'
,controller_files = fs.readdirSync(controllers_path);
controller_files.forEach(function (file) {
require(controllers_path+'/'+file)(app);
});
//Jade configuration
app.configure(function() {
app.set('view options', { layout: false });
app.use(express.static(__dirname + ''));
});
app.listen(3001);
console.log("listening on port %d", app.address().port);
The controller.js
module.exports = function(app, auth){
// Get
app.get('/test1', function(req, res){
res.render('index.jade', {});
});
// Post
app.get('/test2', function(req, res){
res.render('index2.jade', {});
});
};
The index.jade
extends layout
block content
form(method="post", action="/test2")
p
input(type="submit")
The index2.jade
extends layout
block content
p Page 2
The layout.jade
h1 Test layout
block content
Thank you!
The problem is that you don't have a POST handler for /test2. In your HTML, you're specifying method="POST", but in your controller, you're handling the GET method only.
You want to change it to this:
// Post
app.post('/test2', function(req, res){
res.render('index2.jade', {});
});
Incidentally, if you want to handle all request types, you can can use app.all, and then decide what to do based on the method type:
app.all('/test2', function(req, res){
if(req.method==='GET'){
// one response for GET requests
} if(req.method==='POST'){
// another response for POST requests
} else {
// catch all...PUT, DELETE, etc.
}
});