I'm trying to use docpad to handle the rendering in an express application but when attempting to access /contact the request just hangs seemingly indefinitely.
Here is my application:
var express = require('express');
var http = require('http');
var app = express();
var cons = require('consolidate');
var server = http.createServer(app).listen(process.env.PORT || 9778);
app.use(app.router);
// Add DocPad to our Application
var docpadInstanceConfiguration = {
// Give it our express application and http server
serverExpress: app,
serverHttp: server,
// Tell it not to load the standard middlewares (as we handled that above)
middlewareStandard: false
};
var docpadInstance = require('docpad').createInstance(docpadInstanceConfiguration, function(err){
if (err) return console.log(err.stack);
// Tell DocPad to perform a generation, extend our server with its routes, and watch for changes
docpadInstance.action('generate server watch', docpadInstanceConfiguration, function(err){
if (err) return console.log(err.stack);
});
});
app.get('/contact', function(req, res) {
req.templateData = {
weDidSomeCustomRendering: true
};
var d = docpadInstance.getFile({relativePath:'hello.html.md'});
docpadInstance.serveDocument({document: d, req: req, res: res}, function(){});
});
This is pretty much copied straight from the documentation but does not work. Any ideas?
The key is to pass next:
app.get('/contact', function(req, res, next) {
req.templateData = {
weDidSomeCustomRendering: true
};
var d = docpadInstance.getFileAtPath('pages/hello.html');
docpadInstance.serveDocument({document: d, req: req, res: res}, next);
});
https://github.com/bevry/docpad/issues/706
Related
I am working on to do list app using mongoDB and node.js. Basically you type what you want to do then click add. I successfully connected the database but it doesn't show the text that's in the database. It shows only the bullets in the localhost.
Here's the code:
app.get('/', function(req, res) {
db.collection('list').find().toArray(function (err, result) {
console.log(result);
if (err) {return};
console.log(err);
res.render('index.ejs', {list: result})
});
});
app.post('/', function(req, res){
console.log(req.body);
db.collection('list').save(req.body, function(err, result) {
if (err) {return};
console.log(err);
console.log('saved')
res.redirect('/');
})
})
I have validated the code you posted and have revised it slightly with comments.
I hope this helps but it seems that the fault might be in the res.render method that is being used. Please refer to the following code:
// Requires
var express = require('express');
var bodyParser = require('body-parser');
var MongoClient = require('mongodb').MongoClient;
// Instantiation
var app = express();
var mongopath = "mongodb://localhost:27017/BitX";
// Port number the REST api works on
var portnum = 7500;
// MongoDB object
var db = null;
MongoClient.connect(mongopath, function(err,ldb){
db = ldb;
});
// Implement Body Parser
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
// Start the REST service
var server = app.listen(portnum, function() {
var host = server.address().address;
var port = server.address().port;
console.log("Content Provider Service listening at http://%s:%s", host, port);
});
// Default route
app.get('/', function(req, res) {
// Find all items in orders and send back results to a front end
db.collection('orders').find().toArray(function (err, result) {
res.send(result);
// Consider that the rendering engine may not be functioning correctly
// SEE MORE: https://stackoverflow.com/questions/21843840/what-does-res-render-do-and-what-does-the-html-file-look-like
//res.render('index.ejs', {list: result})
});
});
// Accept a post on the root
app.post('/', function(req, res){
//Save into orders
db.collection('orders').save(req.body, function(err, result) {
res.send(true);
//res.redirect('/');
});
});
For additional information on the res.render method please have a look at:
What does "res.render" do, and what does the html file look like?
- if you have not already.
Hope it helps!
I have the following node express function:
var express = require('express');
var app = express();
// Listen on port 8000, IP defaults to 127.0.0.1
var server = app.listen(8000, function() {
console.log("node express app started at http://localhost:8000");
});
app.get("/test",
function(error, request, response, next) {
request.set("Content-Type", "text/html; charset=UTF-8");
if (error) {
request.status(403);
return next();
}
var id = request.query.snuid;
var currency = request.query.currency;
var mac_address = request.query.mac_address;
var display_multiplier = request.query.display_multiplier;
//
request.status(200);
});
When I load up the browser and enter in the url:
http://localhost:8000/test?snuid=1234¤cy=1000&mac_address=00-16-41-34-2C-A6&display_multiplier=1.0
Im not sure why I am getting this error!? Not sure, it should work based on the documentation and examples I have seen. Any help would be appreciated.
I think is because you want to use a middleware and not a route, so maybe your code can be write in this way:
var express = require('express');
var app = express();
app.use(function(err, request, response, next) {
if (error) {
request.status(403);
return next();
}
});
app.get("/test", function(request, response, next) {
response.set("Content-Type", "text/html; charset=UTF-8");
var id = request.query.snuid;
var currency = request.query.currency;
var mac_address = request.query.mac_address;
var display_multiplier = request.query.display_multiplier;
//
response.status(200).end();
});
// Listen on port 8000, IP defaults to 127.0.0.1
var server = app.listen(8000, function() {
console.log("node express app started at http://localhost:8000");
});`
Following is my server file. I am making 2 calls, one post and one get. It works fine at times. But gives an error of : Can't set headers after they are sent. Does this have anything to do with my client side code?
server.js
var express = require('express')
var mongoose = require('mongoose')
var path = require('path')
var bodyParser = require("body-parser")
var cors = require("cors")
var app = express()
var port = process.env.PORT || 3000
var Url = require("./data/url-schema");
//Express request pipeline
app.use(express.static(path.join(__dirname,"../client")))
app.use(bodyParser.json())
app.use(cors());
/*
Your server must be ready to handle real URLs. When the app first loads at / it will probably work, but as the user navigates around and then hits refresh at /dashboard your web server will get a request to /dashboard. You will need it to handle that URL and include your JavaScript application in the response.
*/
app.get('*', function (request, response, next){
response.sendFile(path.resolve(__dirname, '../client', 'index.html'))
next()
})
app.get('/:code', function(req, res) {
console.log("reg", req.params.code)
Url.findOne({code:req.params.code}, function(err, data){
console.log("data", data)
if(data)
res.redirect(302, data.longUrl)
else
res.end()
})
})
app.post('/addUrl', function (req, res, next) {
console.log("on create");
Url.findOne({longUrl:req.body.longUrl}, function(err, data) {
if (err)
res.send(err);
else if(data) {
console.log("already exists",data)
res.send("http://localhost:3000/"+data.code);
} else {
var url = new Url({
code : Utility.randomString(6,"abcdefghijklm"),
longUrl : req.body.longUrl
});
console.log("in last else data created",url)
url.save(function (err, data) {
console.log(data)
if (err)
res.send(err);
else
res.send("http://localhost:3000/"+data.code);
});
}
});
})
app.listen(port, function () {
console.log('Example app listening on port 3000!')
});
// Connect to our mongo database
mongoose.connect('mongodb://localhost/shortUrl');
I get the Following error
error
_http_outgoing.js:335
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (/opt/lampp/htdocs/url-shortener/node_modules/express/lib/response.js:718:10)
at ServerResponse.location (/opt/lampp/htdocs/url-shortener/node_modules/express/lib/response.js:835:8)
at ServerResponse.redirect (/opt/lampp/htdocs/url-shortener/node_modules/express/lib/response.js:874:8)
at Query.<anonymous> (/opt/lampp/htdocs/url-shortener/server/server.js:30:8)
at /opt/lampp/htdocs/url-shortener/node_modules/mongoose/node_modules/kareem/index.js:177:19
at /opt/lampp/htdocs/url-shortener/node_modules/mongoose/node_modules/kareem/index.js:109:16
at process._tickCallback (node.js:355:11)
From the execution order, in * route handler, the body is being assigned to the response and then in /:code, the response code 302 is being added, where Location header is also added, hence the error. Any header must be added before the body to the response.
To solve this problem, simply change the order of the two GET statements.
Finally found the solution:
var express = require('express')
var mongoose = require('mongoose')
var path = require('path')
var bodyParser = require("body-parser")
var app = express()
var port = process.env.PORT || 3000
var Url = require("./data/url-schema")
var Utility = require("./utility")
//Express request pipeline
app.use(express.static(path.join(__dirname,"../client")))
app.use(bodyParser.json())
/*
Your server must be ready to handle real URLs. When the app first loads at / it will probably work, but as the user navigates around and then hits refresh at /dashboard your web server will get a request to /dashboard. You will need it to handle that URL and include your JavaScript application in the response.
*/
app.get('/dashboard', function (request, response, next){
response.sendFile(path.resolve(__dirname, '../client', 'index.html'))
next()
})
app.get('/about', function (request, response, next){
response.sendFile(path.resolve(__dirname, '../client', 'index.html'))
next()
})
app.get('/:code', function(req, res) {
Url.findOne({code:req.params.code}, function(err, data){
if(data){
res.redirect(302, data.longUrl)
}
})
})
app.post('/addUrl', function (req, res, next) {
Url.findOne({longUrl:req.body.longUrl}, function(err, data) {
if (err){
res.send(err)
}
else if(data) {
res.send("http://localhost:3000/"+data.code);
} else {
var newCode = getCode()
checkCode(newCode)
.then(function(data){
var url = new Url({
code : data,
longUrl : req.body.longUrl
});
url.save(function (err, data) {
if (err)
res.send(err);
else
res.send("http://localhost:3000/"+data.code);
});
})
}
});
})
app.listen(port, function () {
console.log('Example app listening on port 3000!')
});
// Connect to our mongo database
mongoose.connect('mongodb://localhost/shortUrl');
//Generate a random code
function getCode() {
return Utility.randomString(6,"abcdefghijklmnopqrstuvwxyz")
}
//Check if the code is unique
function checkCode(code) {
return new Promise(function (resolve, reject){
Url.findOne({code:code}, function(err, data) {
if(err === null){
resolve(code)
}else if(data){
saveUrlCode(getCode())
}
})
})
}
My earlier route which was :
app.get('*', function (request, response, next){
response.sendFile(path.resolve(__dirname, '../client', 'index.html'))
next()
})
The get route was getting executed twice on account of the above call and the
app.get(":/code") call.
So I had to handle the routes properly which I have done by handling the dashboard and about routes separately instead of using the "*" route.
Is there any way to configure a node js application with express js 4 to serve some pages under http protocol and other, those which need more security, in https?
I describe my problem: I'm developing a shop online and I want to display certain pages, like the products list or the product detail views under http, and others which I think need more security, like login or the shopping cart views, under https protocol.
I have tried the express-force-ssl module, but it isn't working. The following code snippet is not from my app (which is too dirty) it is just an example which alos doesn't work for me:
var express = require('express');
var forceSSL = require('express-force-ssl');
var fs = require('fs');
var http = require('http');
var https = require('https');
var ssl_options = {
key: fs.readFileSync('./server-private-key.pem'),
cert: fs.readFileSync('./server-certificate.pem'),
ca: fs.readFileSync('./server-certificate-signing-request.pem')
};
var app = express();
var server = http.createServer(app);
var secureServer = https.createServer(ssl_options, app);
app.use(forceSSL);
app.get('/', function (req, res, next) {
res.send('Hello')
});
app.get('/user/:name', function (req, res, next) {
var user = req.params.name;
res.send('Hello ' + user + '')
});
app.get('/login', forceSSL, function (req, res, next) {
res.send('Hello<br/>Goodbye')
});
app.get('/logout', forceSSL, function (req, res, next) {
res.send('Hello')
});
secureServer.listen(443)
server.listen(8085)
console.log('server started');
The result is that when I launch the application, with url http://localhost:8085, the server automatically redirects it to https://localhost and serves all pages in https protocol.
What I want is to start on http://localhost:8085, navigate to http://localhost/user/userA, then from it go to https://localhost/login and, if click on "Hello" link, I would like to be redirected to http://localhost:8085.
Is there any missing code to get the behavior I want or even any other way to reach it without express-force-ssl module?
I have asked to the author of express-force-ssl module and he has told me that the redirect behavior works as expected. Here is the post.
But diving a little more in its code I've created a custom plugin to solve my problem. Here is the code:
var parseUrl = require('url').parse;
var isSecure = function (req) {
if (req.secure) {
return true;
}
else if (
req.get('X-Forwarded-Proto') &&
req.get('X-Forwarded-Proto').toLowerCase &&
req.get('X-Forwarded-Proto').toLowerCase() === 'https') {
return true;
}
return false;
};
exports = module.exports = function (req, res, next) {
if (isSecure(req)) {
if (req.method === "GET") {
var httpPort = req.app.get('httpPort') || 80;
var fullUrl = parseUrl(req.protocol + '://' + req.header('Host') + req.originalUrl);
res.redirect('http://' + fullUrl.hostname + ':' + httpPort + req.originalUrl);
}
else {
next();
}
}
else {
next();
}
};
It's very similar to force-ssl file but here we manage the opposite action, i.e., here I redirect to http when a route is forced to it. So it's needed to add the function to every route we want to see under http protocol:
var express = require('express');
var forceSSL = require('express-force-ssl');
var fs = require('fs');
var http = require('http');
var https = require('https');
var useHttp = require('./useHttp');
var ssl_options = {
key: fs.readFileSync('./server-private-key.pem'),
cert: fs.readFileSync('./server-certificate.pem')
};
var app = express();
var server = http.createServer(app);
var secureServer = https.createServer(ssl_options, app);
app.get('/', useHttp, function (req, res, next) {
res.send('Hello')
});
app.get('/user/:name', useHttp, function (req, res, next) {
var user = req.params.name;
res.send('Hello ' + user + '')
});
app.get('/login', forceSSL, function (req, res, next) {
res.send('Hello<br/>Goodbye')
});
app.get('/logout', forceSSL, function (req, res, next) {
res.send('Hello')
});
app.set('httpsPort', 9090);
app.set('httpPort', 8085);
secureServer.listen(9090)
server.listen(8085)
console.log('server started');
As you can see I need now to specify in all routes which protocol use: useHttp for http or forceSSL for https.
Although I'm not comfortable at all with this solution because I have to specify in all routes which kind of protocol I want. But at least it works. So I would be very pleased if someone finds any other solution, for isntance, adding in middleware layer a function to manage all http requests and just redirect to https when it is specified with forceSSL. By the moment, this works.
I am getting my hands on node.js and I am trying to understand the whole require/exports thing. I have the following main app.js file:
/app.js
var express = require('express'),
http = require('http'),
redis = require('redis'),
routes = require('./routes'),
var app = express(),
client = redis.createClient();
// some more stuff here...
// and my routes
app.get('/', routes.index);
then, I have the routes file:
exports.index = function(req, res){
res.render('index', { title: 'Express' });
};
I can of course use the client object on my app.js file, but how can I use the same object in my routes?
Since req and res are already being passed around by Express, you can attach client to one or both in a custom middleware:
app.use(function (req, res, next) {
req.client = res.client = client;
next();
});
Note that order does matter with middleware, so this will need to be before app.use(app.router);.
But, then you can access the client within any route handlers:
exports.index = function(req, res){
req.client.get(..., function (err, ...) {
res.render('index', { title: 'Express' });
});
};
The easiest way is to export a function from your routes file that takes a client, and returns an object with your routes:
exports = module.exports = function (client) {
return {
index: function (req, res) {
// use client here, as needed
res.render('index', { title: 'Express' });
}
};
};
Then from app.js:
var client = redis.createClient(),
routes = require('./routes')(client);