Express 4.x Prepend cookie to static contents? - node.js

Is it possible to set a cookie to a static content request using Express? For instance I'm trying to append the cookie "foo" to any request that doesn't have that cookie value set, before sending static contents such as index.html.
var express = require("express");
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser());
app.use(function(req, res, next){
if(!req.cookies || !req.cookies.foo){
res.cookie("foo", "bar");
}
next();
});
app.use(express.static('public'));
My problem is that this flat out doesn't work. I can set a cookie if I add send onto the end, but it either requires a dedicated url call, or terminates the response when thew original intended target was "index.html", then placed towards the front of the router.
app.get('/cookie',function(req, res){
res.cookie('foo' , 'bar').send('Cookie is set');
});
Do I need to do something like check every request, set the cookie, and then set a redirect for the same url to get the original indented request (index.html, etc)?

This looks weird:
if (!req.cookies || req.cookies.foo)
For one, req.cookies will always be defined by cookie-parser. If there weren't any cookies passed in the request, it will be an empty object (which will evaluate to true). Also, it looks like you want to set a cookie foo only if it's set already?
I think you want this instead:
if (! req.cookies.foo) {
res.cookie(...);
}

Related

nodejs, how to using module.exports to set multiple parameters in express router

for example:
app.js:
var express = require('express');
var app = express();
var routesTemp=require('./routes/temp');
var routesTempExport=require('./routes/temp_export');
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'mustache');
app.engine('mustache', require('hogan-middleware').__express);
app.use('/',routesTemp);
app.use('/',routesTempExport);
module.exports = app;
/routes/temp.js:
var express = require('express');
var router = express.Router();
router.get('/temp',function(req, res, next){
//how to set a object,function...etc in there to module.exports
res.end();
});
// or there to set
module.exports = router;
/routes/temp_export.js:
var express = require('express');
var router = express.Router();
var getParameters = require('./temp');
router.get('/temp_export',function(req, res, next){
//and how to use getParameters to get multiple;
res.end()
});
module.exports = router;
I tried to change the module.exports format
for example:
module.exports = {router:router,obj1:obj1};
module.exports = [router,obj1];
module.exports = router,obj1;
But did not succeed, and will lead to router can not be identified
If you set this in your module:
// in myModule.js
module.exports = {router:router,obj1:obj1};
Then, you can access both variables upon import by:
const myModule = require('myModule.js');
console.log(myModule.router);
console.log(myModule.obj1);
You do have to make absolutely sure that the two exported properties are already set when you export. If they get set sometime in the future via some async operation, then you have no idea if they will be set properly when you want to use them.
In looking at the comments in your code some more, it appears that you're trying to use a value computed in a route in temp.js, in a separate route in temp_export.js. You basically can't do that directly because routes come from all sorts of users so you can't store state from one route in any sort of global on your server and expect some other route to access that state (well, you could, but it wouldn't work properly most of the time).
Instead, what you would typically do is store that state in some way that is clearly identified with a specific client. Then, when that particular client makes the next request and that route gets the request, that route handler can check the client-specific store to see if there is some state there. Note that creating this state in the first place violates some principles of the REST design so your first design idea should be how to avoid doing this at all. It would be better to put the state into the webpage returned from the first route and then when it makes the next web request, it can include that state in a query parameter.
The usual places you can store client-specific state are:
By putting it into the returned web page (so the client can pick up that state to send it with the next request - often as a query parameter or in a form post).
By putting the state into a cookie. The cookie values will then be available to the server upon the next request.
By storing it in a server-side session that is uniquely tied to that browser/user. The server-side session state for a particular user is also available to the server upon the next request.
Remember that the more stateless your server is the better (in general). So, if there is temporary state relevant to a particular user, you'd like that to be stored in the browser and presented back to the server with the next request, rather than having the server try to keep track of it in between requests.

Node Express auth status

I have multiple routes, split into different files (my app consists of different "modules", which I maintain in separate folders. For each folder, there is an index.js file in which I manage the routes per module, and I require these in the app.js file).
For every route, I will require to check the auth, and pass the loggedIn status to the header of every page:
//Default variables for the ejs template
var options = {
loggedIn: true
};
res.render("home/home", options);
If the logged in status is true, then the user's name will be displayed. If not, the login / signup labels are displayed.
What is the best way to centralise this, so that I don't need to require the auth script in every of these index.js (route) files?
I need to be able to pass the auth status to the view via the options object (see example).
In your auth, module, use a middleware function. That function can check and store res.locals.loggedIn which will be available for any view that will eventually be rendered. Just make sure the app.use call executes prior to your other routes and it will work properly.
app.use(function auth(req, res, next) {
res.locals.loggedIn = true; // compute proper value here
next();
});
From what I understand you need to do this for every request.One common thing is adding this as middleware so that all the request gets this .
For Example :
var http = require('http');
var connect = require('connect');
var app = connect();
app.use(function(req, res) {
res.end('Hello!');
});
http.createServer(app).listen(3000)
Now for every request , Hello is printed . You could extract this as a module and reuse it across projects. Check here for more details

Node.js variables for current request only?

I am very new to Node.js, and I was wondering if that, except for session(), I could use a "storage" to store variables for the current request?
I have an API which is based on an Authorization header, and a pool of valid tokens stored in Redis.
Therefore I don't have a session and don't want to.
But I would like to store variables for further use during this request. For example, I would like to store the user_id corresponding to the token found in Redis, so that I can use it wherever I want.
If I do something like:
app = express();
app.user_id = 1;
Is it ok, or will my user_id become global to all requests handled by the app? (in short: is the app instanciated for each request handled by the server, or is it persistent?)
If this is not ok, how could I achieve something like this without sessions?
Thank you for any help :)
The app handles all requests, and would only be created once on startup, but req lives for only the lifetime of the request. Keep in mind that the req in Express is just an object, and as such, can be assigned values. So if you wanted to allow the controller to have access to some value (similar to sessions), you could do something like this:
var express = require('express');
var app = express();
// middleware that assigns a value '123' to 'req.user_id'
app.use(function(req, res, next) {
req.user_id = 123;
next();
});
// controller which responds with the 'req.user_id'
app.get('/hello', function(req, res){
res.send('req.user_id: ' + req.user_id); // responds with req.user_id: 123
});
app.listen(3000, function() {
console.log('Listening on port 3000');
});
In the above example, the middleware that I created assigns a value to the request, called user_id. This value lives for the life of the request. You could do a similar thing to assign a dynamic value to the req so that you can access it via your controllers.

Multi-language routes in express.js?

I'm wondering if there is a best practise example on how to implement multi-lanuage routes in express.js. i want to use the accept-language header to get the browser language and then redirect automatically to the corresponding language route like
www.foo.bar/de/startseite OR
www.foo.bar/en/home
Any advice on this?
i have done the following:
install i18n-node modul and register in the express js. here is code.
var express = require('express')
, routes = require('./routes')
, http = require('http')
, i18n = require("i18n");
var app = express();
i18n.configure({
// setup some locales - other locales default to en silently
locales:['de', 'en'],
// disable locale file updates
updateFiles: false
});
app.configure(function(){
...
app.use(i18n.init);
...
});
// register helpers for use in templates
app.locals({
__i: i18n.__,
__n: i18n.__n
});
after this set the following to get all request
// invoked before each action
app.all('*', function(req, res, next) {
// set locale
var rxLocal = /^\/(de|en)/i;
if(rxLocal.test(req.url)){
var arr = rxLocal.exec(req.url);
var local=arr[1];
i18n.setLocale(local);
} else {
i18n.setLocale('de');
}
// add extra logic
next();
});
app.get(/\/(de|en)\/login/i, routes.login);
maybe this help.
I'd just serve up the content in the detected language directly.
For example, example.com/home serves up the home page in the best available Accept-Language (possibly overridden by cookie if you provide a language selection option on the site itself).
You'd want to make sure that your response's Vary: header includes Accept-Language.
IMO, including language codes in the URI is an ugly hack. The RFC's intent is that a single resource (your home page) is universally represented by a single URI. The entity returned for a URI can vary based on other information, such as language preferences.
Consider what happens when a German-speaking user copies a URL and sends it to an English-speaking user. That recipient would prefer to see your site in English, but because he has received a link that points to example.com/de/startseite, he goes straight to the German version.
Obviously, this isn't ideal for full internationalization of what the user sees in the address bar (since home is English), but it's more in line with the RFCs' intent, and I'd argue it works better for users, especially as links get spread around email/social/whatever.
Middleware recommendation
The answer by #miro is very good but can be improved as in the following middleware in a separate file (as #ebohlman suggests).
The middleware
module.exports = {
configure: function(app, i18n, config) {
app.locals.i18n = config;
i18n.configure(config);
},
init: function(req, res, next) {
var rxLocale = /^\/(\w\w)/i;
if (rxLocale.test(req.url)){
var locale = rxLocale.exec(req.url)[1];
if (req.app.locals.i18n.locales.indexOf(locale) >= 0)
req.setLocale(locale);
}
//else // no need to set the already default
next();
},
url: function(app, url) {
var locales = app.locals.i18n.locales;
var urls = [];
for (var i = 0; i < locales.length; i++)
urls[i] = '/' + locales[i] + url;
urls[i] = url;
return urls;
}
};
Also in sample project in github.
Explanation
The middleware has three functions. The first is a small helper that configures i18n-node and also saves the settings in app.locals (haven't figured out how to access the settings from i18n-node itself).
The main one is the second, which takes the locale from the url and sets it in the request object.
The last one is a helper which, for a given url, returns an array with all possible locales. Eg calling it with '/about' we would get ['/en/about', ..., '/about'].
How to use
In app.js:
// include
var i18n = require('i18n');
var services = require('./services');
// configure
services.i18nUrls.configure(app, i18n, {
locales: ['el', 'en'],
defaultLocale: 'el'
});
// add middleware after static
app.use(services.i18nUrls.init);
// router
app.use(services.i18nUrls.url(app, '/'), routes);
Github link
The locale can be accessed from eg any controller with i18n-node's req.getLocale().
RFC
What #josh3736 recommends is surely compliant with RFC etc. Nevertheless, this is a quite common requirement for many i18n web sites and apps, and even Google respects same resources localised and served under different urls (can verify this in webmaster tools). What I would recommended though is to have the same alias after the lang code, eg /en/home, /de/home etc.
Not sure how you plan on organizing or sharing content but you can use regular expressions with express routes and then server up different templates. Something like this:
app.get(/^\/(startseite|home)$/, function(req, res){
});
One thing that I did was to organize my content with subdomains and then use middleware to grab the content out of the database based splitting the url, but they all shared the same routes and templates.
Write a middleware function that parses any "Accept-Language" headers and sets a request-level local variable to an appropriate code (like a two-letter language code) with a default value (like "en") if there are no such headers or you don't support any language listed. In your routes, retrieve the local and tack it on to any template file names, and branch on it if there's any language-dependent processing other than template selection.

More sophisticated static file serving under Express

Best explained by an example. Say I have a directory /images, where I have images a.png, b.png, and c.png.
Then I have a directory /foo/images, which has an image b.png, which is different than the b.png in /images.
I want it so if a request comes in for http://mydomain.com/foo/images/a.png, it will serve the image /images/a.png. But if a request comes in for http://mydomain.com/foo/images/b.png, it will get the version of b.png in /foo/images. That is, it first checks foo/images/ and if there is not file by that name, it falls back on /images.
I could do this using res.sendfile(), but I'd prefer use built-in functionality if it exists, or someone's optimized module, while not losing the benefits (caching, etc) that might be provided by the middleware.
This would intercept requests to /foo/images/ and redirect them if the file doesn't exist, still using static middleware and caching appropriately
var imageProxy = require('./imageProxy.js');
// intercept requests before static is called and change the url
app.use( imageProxy );
// this will still get cached
app.use( express.static(__dirname + '/public') );
And inside imageProxy.js:
var url = require('url');
var fs = require('fs');
var ROOT = process.execPath + '/public';
exports = function(req, res, next) {
var parts = url.parse(req.url);
// find all urls beginnig with /foo/images/
var m = parts.pathname.match(/^(\/foo(\/images\/.*))/);
if( m ) {
// see if the override file exists
fs.exists(ROOT+m[1], function (exists) {
if( !exists ) { req.url = ROOT+m[2]; }
// pass on the results to the static middleware
next();
});
}
});
If you wanted to access the original URL for some reason, it's still available at req.originalUrl

Resources