How can I escape routes in Express and Node.js when using the /: notation? Here's what I'm doing:
app.get('/:route1/:route2', function(req, res){
var route1 = req.params.route1;
var route2 = req.params.route2;
MongoClient.connect(MongoUrl, function(err, db) {
if(err) throw err;
db.collection(route1)
.findOne({'_id' : new ObjectID(route2)},
function(err, doc){
res.send(doc);
});
});;
But by doing that, it won't load the js or css. I've tried if statements to no avail:
if(req.params.route1 !== 'javascripts'){//then do something}
First, without any knowledge of what you're doing or how your app is structured, I can't say for sure, but:
What you're doing (routes like /:var1/:var2) is a code smell to me. If api.function looks something like
if (req.params.var1 == 'foo') {
// do stuff
} else if (req.params.var1 == 'bar') {
// do other stuff
}
...that's not really the correct way to structure an Express application. In general, it should look more like
app.get('/foo/:var2', function(req, res) {
// do stuff
});
app.get('/bar/:var2', function(req, res) {
// do other stuff
});
That being said, if you really need to have your route handler ignore a certain value, you could just call next:
app.get('/:route1/:route2', function(req, res, next) {
if (req.params.route1 == 'javascripts') next();
else {
// do something
}
});
Are you using the connect static middleware?
app.use(express.static(__dirname + 'public'))
This says "any request to a file in the /public folder, serve it as a static file".
Make sure this appears above any app.get routes, so it will be used first.
you should move your static middleware above your route
app.use(express.static(path.join(__dirname, 'public')));
app.use(app.router);
app.get('/:route1/:route2', api.function);
Related
I don't know if it's possible, but I need to loading dinamically route files in middleware, according to a conditional.
Here we have the code that do well job in the first request, but seems that in next request, he enters inside right place of conditional but not use right file, seems that he uses cache file or something of previous request...
let routesApp = require('./routes-app');
let routesWeb = require('./routes-web');
app.use((req, res, next) => {
const regex = new RegExp(pattern, 'i')
if (regex.test(req.headers['agent-type'])) {
app.use('/', routesWeb)
} else {
app.use('/', routesApp)
}
return next()
})
How do I make this works?
When you call app.use the middleware passed to it gets registered for that path and subsequent requests will be handled by that .
One way to handle what you are doing is define a middleware which conditionally delegates to your web or mobile middleware as needed.
Sample Code:
let routesApp = require('./routes-app');
let routesWeb = require('./routes-web');
app.use('/', (req, res, next) => {
const regex = new RegExp(pattern, 'i')
if (regex.test(req.headers['agent-type'])) {
routesWeb(req, res, next);
} else {
routesApp(req, res, next);
}
})
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
I need to grab the rawBody (buffer) for a POST request, but I only need to do this on a single route in my application.
Currently, I'm using the following in my main app.js:
app.use(bodyParser.json({ verify: function(req, res, buf) { req.rawBody = buf; }}));
This works, but it is sending the buffer for every route. This is undesirable because it uses twice the RAM for every request in my app.
How can I instead obtain the rawBody on the single route I need it for?
Typically, you'd create that single route and inline the middleware:
app.post('/route', bodyParser.json(...), function(req, res) {
...
});
Followed by the "normal" setup:
app.use(bodyParser.json());
app.post('/another-route', function(req, res) {
...
});
Instead of abusing bodyParser.json(), you could also consider using bodyParser.raw().
If its trivial to refer to the specific route then this would work.This is a very simplistic representation of the idea:
var routeIWantToBuffer = "someroute";
app.use(bodyParser.json(
{
verify: function(req, res, buf) {
if(req.route === routeIWantToBuffer) req.rawBody = buf;
}
}
));
Usually route/use functions also have a next argument which is used to continue the chain. I'm not saying this is wrong, but I don't know what the rest of your code looks like. But I would expect it to look like this:
var routeIWantToBuffer = "someroute";
app.use(bodyParser.json(
{
verify: function(req, res, buf, next) {
if(req.route === routeIWantToBuffer) req.rawBody = buf;
next();
}
}
));
I'm using Nodejs and Expressjs and Kraken, I need to display message when added a product on index but I tried many time for to config but messages still not appear as I expect. Here is my config.js:
var flash = require('connect-flash');
app = module.exports = express();
app.use(kraken(options));
//flash
app.use(flash());
app.use(function (req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
My controller :
router.post('/somePath', function (req, res) {
//something to do to add
res.flash('messages','Add success!!')
res.render('path/index');
});
My index.dust file:
`{>"layouts/master" /}
{<body}
{messages|s}
// body goes here
{/body}
`
You're pretty close to the answer.
This line
res.locals.messages = require('express-messages')(req, res);
Stores a function in messages that outputs the flash messages as an html fragment.
res.locals is merged by express with the models that are used to render your template.
Now you just need a way to invoke this function from within the dust template.
Doing this:
{messages|s}
Doesn't actually invoke the function. You need to call it as if it were a context helper:
{#messages /}
You'll have one last hurdle to clear.
The function signature that express-messages expects, is different from what dust provides, so you'll have to wrap it within a helper function (in your server.js file):
app.use(flash());
app.use(function (req, res, next) {
var messages = require('express-messages')(req, res);
res.locals.messages = function (chunk, context, bodies, params) {
return chunk.write(messages());
};
next();
});
I was wondering how should I be dealing with response and next in express.
My understanding is that when I say res.send(...) -> returns a response
If I want to throw an error, I say next(new Error('whatever')) -> auto sets the http status code using express errorhandler.
I am able to do either of those but not but, looks like I am messing up.
Can anyone give an example?
I tried,
somefunc(err, req, res, next) {
if(err) {
res.send(500, 'some error');
return next(err);
}
}
return [somefunc, express.errorHandler()];
thanks.
You can register some middleware to handle errors:
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
You can also simply send a 500 with your response if you encounter an error in your logic
function loginUser(req, res, next) {
try {
var valid;
//code to check user
if (valid) {
next();
} else {
res.send(401, 'not authorized');
}
} catch (err) {
res.send(500, 'Oopsy');
}
}
app.get('/some/route',loginUser, function(req, res) {
// ...
});
Just skip return next(); part. Use return res.send(500,'some error'); Calling next causes next middleware to be called which IMO is not what you want in this case. I wrote more about it here.
Here is minimal example of express stack:
express = require('express');
app = express();
app.configure(function() {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(app.router());
app.use(express.static(__dirname + '/public'));
});
app.get('/', function(req, res) {
if (some error)
res.send(500, 'Some error');
else
res.send('<body>Hello</body>');
});
app.listen(3000); // listen on port 3000
The get request will be called by router middleware. Middlewares are parsed as chain. You can use custom middleware in this chain, for example:
app.configure(function() {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(function(req, res, next){
if (some condition)
res.send(500, 'No way'); // this will break the request chain
else
next(); // this will continue processing and will call app.router middleware
});
app.use(app.router());
app.use(express.static(__dirname + '/public'));
});
app.router middleware is responsible for calling appropriate method based on requested URL (like app.get('/')). If it fails to find one, it calls next() to pass control to express.static middleware which tries to find static file in /public/ folder.