Say I have this code in node.js:
app.post('/stuff', function(req, res){
res.send('hello world');
});
app.route('*').all(function(req,res,next){
res.write('Hello World');
});
There are 2 routes here - one is a catch-all for any request to the server and the other is what to do if a post request with a route of /stuff is sent.
Is it possible to pass a value local to the post request into route?
Intended Program flow: initial request to the server goes through route (which has controls not illustrated to ignore post requests) and the connection is left open, then a post request is sent from the initial request and is dealt with by app.post - can a value found within the closure of post be passed to the initial request that is still open?
I am trying to avoid using Global variables, and res.local only has a local scope. Also trying to keep clean so if I can use native express or node.js all the better. Much obliged for any help.
then a post request is sent from the initial request
Why don't you simply pull out the POST function and call it from both handlers, that way you don't need to send a seperate request from inside your app.
var postHandler = function(req, res) {
res.send('hello world');
// Just return whatever you want back to the calling function
return someValue;
};
// Set it as the handler for post.
app.post('/stuff', postHandler);
app.route('*').all(function(req,res,next){
// Call function.
var returnValue = postHandler(req, res);
res.write('Hello World');
});
app.route('*').all(function(req,res,next){
if (req.originalUrl === '/stuff') {
req.variable = 'some value';
return next();
};
res.write('Hello World');
});
app.post('/stuff', function(req, res){
var value = req.variable;
res.send('hello world');
});
You can try this code. Please take the order of app.all and app.post.
The second way, your can try app.locals http://www.expressjs.com.cn/4x/api.html#app.locals
The app.locals object is a JavaScript object, and its properties are
local variables within the application.
Related
I have a server that is fully functioning, but I only want it to be accessable when I say. I do this via a discord bot which works fine. I currently have a boolean variable server_on and an if (server on) { do } in all of my app.get and app.post functions. Is there a cleaner way to do this, or is this if statement in every function the only way?
Edit:
Final working code
var block_server_middleware = function (req, res, next) {
if (!server_on) { res.send("server is currently unavailable") }
else { next() }
}
app.use(block_server_middleware)
and the other app.get and app.post functions were not changed at all
This was the only few lines added that made the whole idea work
You can define one middleware function that goes before all your routes are defined:
app.use((req, res, next) => {
if (!server_on) {
// stop all routing
res.send("server not on!");
} else {
// let routing continue
next();
}
});
This will keep your routes from ever getting run until server_on is back to true. If you have any routes you want to leave open all the time, then just place them before this middleware.
You can replace res.send("server not on!"); with whatever is appropriate for your use. You can return a single web page or you can send back a 4xx or 5xx error status (perhaps a 503 error).
Situation
I have a html page which calls multiple javascript files. Everything works on client-side right now.
Because I need to execute a jar within javascript, I am switching to Node.js. (applets are deprecated)
However, I am new to node.js and confused about how to link everything.
I have :
index.html which calls various .js scripts (files.js,objects.js,etc.)
webServer.js which makes the node.js server
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
fs.readFile('index.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end();
});
}).listen(8080);
javaApp.js which executes a jar
var exec = require('child_process').exec;
var child = exec('java -jar E:/JavaApp.jar',
function (error, stdout, stderr){
console.log('Output -> ' + stdout);
if(error !== null){
console.log("Error -> "+error);
}
});
module.exports = child;
The question
I would like, when clicking on a button in my html, to call javaApp.js on the server side.
I know Express can be used to link index.html to webServer.js, but I don't understand how to link index.html to the code used by the server.
i.e. How can I call javaApp.js from index.html if there's no function name in it?
Is this answer relevant ? How to call node.js server side method from javascript?
If you want to call the jar on the server you have to create a route for it(maybe using express).
router.get('/call-java-app', function (req, res, next){
//call you function in here
//respond with any data you want
res.send('Your data here');
});
Your button would have to make a get request at /call-java-app and optionally wait for any response from the server.
var url = '/call-java-app';
console.log(url);
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState === 4) {
//handle server response here if you want to
}
}
xmlHttp.open("GET", url, true); // false for synchronous request
xmlHttp.send(null);
How can I call javaApp.js from index.html if there's no function name in it?
You can't. At least not sensibly.
Change it so it exports a function you can call if you want to call it multiple times.
Since it is asynchronous, you should make that function return a Promise.
In your webserver, require the module you write to get access to the function it exports.
Write a route which calls that function and returns a suitable HTTP response.
Then cause the browser to make an HTTP request to that route by clicking a link, submitting a form, using fetch, or whatever other method you like.
Your webserver is now as simple as it (almost) can be. Just sending index.html when the ip+port 8080 is called with http (get).
Before you can use your jar-module you have to make a requiere in your webserver:
var child = require('javaApp')
This will give you access to "child" wrappet with a error-function. What "child" actual is doing and can do, you probably know (i hope). If you skip the index.html you can send some response from your "child" to see how it works.
Let's say I have this:
a) 2 routes with 1 middleware function each and a callback function:
router.post('/foo', fooCtrl, function(req, res)
{
res.redirect('/bar');
});
router.get('/bar', barCtrl, function(req, res)
{
res.end('finished');
});
b) 2 middleware function expressions
fooCtrl = function(req, res, next)
{
req.foo = 'foo';
next();
};
barCtrl = function(req, res, next)
{
console.log(req.foo); // output is 'undefined'
next();
};
As you can see, in the fooCtrl I'm setting a variable req.foo - and in this scope it is set than... but I'm not able to call this variable in the barCtrl-scope.
Isn't the req object passed by reference?
Any suggestions or best practices?
The purpose of this is to pass a token after login from the login-controller to an admin-controller .. something like that.
That is the expected behaviour. req object is created anew for each new request and your redirection i.e. res.redirect('/bar') results in a new request.
Solution:
You may use some package e.g.connect-flash which stores variables in a temporary session object, which can be used only once. You need to set required values in your flash objects before redirecting. Then after redirection, you will be able to get the saved values from the flash object itself.
Inspired by How to share sessions with Socket.IO 1.x and Express 4.x? i implemented socket authentication in some "clean" way where is no need to use cookie-parser and to read cookies from headers, but few items remain unclear to me. Example use last stable socket.io version 1.3.6.
var express = require('express'),
session = require('express-session'),
RedisStore = require('connect-redis')(session),
sessionStore = new RedisStore(),
io = require('socket.io').listen(server);
var sessionMiddleware = session({
store : sessionStore,
secret : "blabla",
cookie : { ... }
});
function socketAuthentication(socket, next) {
var sessionID = socket.request.sessionID;
sessionStore.get(sessionID, function(err, session) {
if(err) { return next(err); }
if(typeof session === "undefined") {
return next( new Error('Session cannot be found') );
}
console.log('Socket authenticated successfully');
next();
});
}
io.of('/abc').use(socketAuthentication).on('connection', function(socket) {
// setup events and stuff
});
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
app.use(sessionMiddleware);
app.get('/', function(req, res) { res.render('index'); });
server.listen(8080);
index.html
<body>
...
<script src="socket.io/socket.io.js"></script>
<script>
var socket = io('http://localhost:8080/abc');
</script>
</body>
So io('http://localhost:8080/abc'); from client-side will send initial HTTP handshake request to server, from where server can gather cookies and many others request informations. So server has access to that initial request via socket.request.
My first question is why handshake request is not in scope of express-session middleware?(More generally in scope of app.use middlewares?) In some way i expected this app.use(sessionMiddleware); to fire before that initial request, and then to access easily to socket.request.session
Second, what are the scenarios in which middlewares defined with io.use() will fire? Only for initial HTTP handshake request? It seems like io.use() is used for socket related stuff(question is: what stuff), while app.use for standard requests.
I'm not quite sure why in the above example io.use() is fired before io.of('/abc').use(). Intentionally i wrote that order putting io.of('/abc').use() first to see will it work and it work.
Should have been written conversely.
Lastly, socket.request.res like pointed also from some people in linked question, sometimes is undefined causing app to broke, problem can be solved by providing empty object instead of socket.request.res, like: sessionMiddleware(socket.request, {}, next); which seems to me like a dirty hack. For what reasons socket.request.res yield to undefined?
Despite #oLeduc is kind of correct, there are a few more things to explain..
Why the handshake's request is not in scope of express-session middleware?
The biggest reason here is that the middleware in express is designed to handle request specific tasks. Not all, but most of the handlers use the standard req, res, next syntax. And sockets are "request-less" if I can say. The fact that you have socket.request is due to the way the handshake is made, and that it is using HTTP for that. So the guys at socket.io hacked that first request into your socket class so that you can use it. It was not designed by the express team to ever work with sockets and TCP.
What are the scenarios in which middlewares defined with io.use() will fire?
io.use is a close representation of the express use middleware way. In express, the middleware is executed on each request, right? But sockets do not have requests and it will be awkward to use middleware on each socket emit, so they've made it to be executed on each connection. But as well as the express middleware is stacked and used before the actual request is handled (and responded), Socket.IO uses the middleware on connection and even before the actual handshake! You can intercept the handshake if you want to, using that kind of middleware, which is very handy (in order to protect your server from spamming). More on this can be found in the code of passport-socketio
Why io.use() fires before io.of('/abc').use()?
The real explanation on this can be found here, which is this code:
Server.prototype.of = function(name, fn){
if (String(name)[0] !== '/') name = '/' + name;
if (!this.nsps[name]) {
debug('initializing namespace %s', name);
var nsp = new Namespace(this, name);
this.nsps[name] = nsp;
}
if (fn) this.nsps[name].on('connect', fn);
return this.nsps[name];
};
And in the beginning of the code, there is this line of code:
this.sockets = this.of('/');
So, there is a default namespace created at the very beginning. And right there, you can see that it has immediately a connect listener attached to it. Later on, each namespace gets the very same connect listener, but because Namespace is EventEmitter, the listeners are added one after another, so they fire one after another. In other words, the default namespace has it's listener at first place, so it fires first.
I don't think this is designed on purpose, but it just happened to be this way :)
Why is socket.request.res undefined?
To be honest, I'm not pretty sure about that. It's because of how engine.io is implemented - you can read a bit more here. It attaches to the regular server, and sends requests in order to make a handshake. I can only imagine that sometimes on errors the headers are separated from the response and that's why you won't get any. Anyways, still just guessing.
Hope information helps.
Why the handshake's request is not in scope of express-session middleware?
Because socket.io will attach to a http.Server which is the layer under express. It is mentioned in a comment in the source of socket.io.
The reason for this is because the first request is a regular http request used to upgrade the reqular stateless http connection into a state-full websocket connection. So it wouldn't make much sense for it to have to go through all the logic that applies to regular http requests.
What are the scenarios in which middlewares defined with io.use() will fire?
Whenever a new socket connection is created.
So every time a client connects it will call the middlewares registed using io.use(). Once the client is connected however, it is not called when a packet is received from the client. It doesn't matter if the connection is initiated on a custom namespace or on the main namespace, it will always be called.
Why io.use() fires before io.of('/abc').use()?
Namespaces are a detail of socket.io's implementation, in reality, websockets will always hit the main namespace first.
To illustrate the situation, look at this snippet and the output it produces:
var customeNamespace = io.of('/abc');
customeNamespace.use(function(socket, next){
console.log('Use -> /abc');
return next();
});
io.of('/abc').on('connection', function (socket) {
console.log('Connected to namespace!')
});
io.use(function(socket, next){
console.log('Use -> /');
return next();
});
io.on('connection', function (socket) {
console.log('Connected to namespace!')
});
Output:
Use -> /
Main namespace
Use -> /abc
Connected to namespace!
See the warning that the socket.io team added to their documentation:
Important note: The namespace is an implementation detail of the Socket.IO protocol, and is not related to the actual URL of the underlying transport, which defaults to /socket.io/….
Why is socket.request.res undefined?
As far as I know it should never be undefined. It might be related to your specific implementation.
I have a Jade file that all of my templates extend called layout.jade. In it I want to be able to have a logout button if the user is currently logged in (this is kept track of in req.session).
So layout.jade will have something like,
-if (loggedin)
a.navButton(href="/logout") Log Out
The route for a page would look something like,
app.get("/foo", function(req, res) {
res.render("foo", {loggedin: req.session.isValidUser});
});
The thing is, I don't want to have to populate the loggedin variable manually in every single route. Is there a way I can use Express middleware to automatically set some default options for the object sent to res.render? Or is there a better method to do this?
Basically I'm asking how I can have some set of variables always sent to templates, as well as the ability to have certain custom variables available in certain templates by manually setting them in the routes.
It seems this is actually a documented feature I just had trouble finding, unless anyone has a better way of doing it; From the latest Express documentation,
app.locals: Application local variables are provided to all templates
rendered within the application. This is useful for providing helper
functions to templates, as well as app-level data.
So in my login success function has,
req.session.username = profile.username;
app.locals.username = profile.username;
My logout function,
app.get('/logout', function (req, res) {
delete app.locals.username;
req.session.destroy();
res.redirect('/login');
});
And finally in layout.jade/all of my templates,
- if(username)
a.navButton(href="/logout") Logout
If you set res.locals.loggedin in the /login route, as hexacyanide suggests, this local will not be available in the route for /foo. res.locals is cleared upon every request.
you could instead try placing this above other routes:
app.all('*', function(req, res, next){
if(req.user){
res.locals.loggedin = true;
res.locals.currentuser = req.user;
};
next();
});
Pretty sure that if you modify req.user during your route, the res.locals.currentuser that you set before won't updated to be the new req.user. but not certain about that.
I actually use a custom render function for each page where I render a template, it looks like this:
function myRender(templateName){
return function(req, res){
res.locals.currentuser = req.user || null;
res.render(templateName);
};
};
and I use it like this:
app.get('/foo'
, function(req, res, next){
res.locals.bar = req.query['bar'] || "";
console.log('passing request to myRender middleware');
next();
}
, myRender('foo-jade-template')
)
This has the advantage of only setting res.locals.currentuser when I am ready to render something, instead of before executing my route. So if I change req.user it is guranteed to have the most recent version at render time.
There is a line of code that is rather useful to you in the Express source:
// merge res.locals
options._locals = self.locals;
Therefore, when you run res.render(), Express will also take any locals that are stored in res.locals and pass them into the render. Therefore, all you have to do is set res.locals.loggedin to true, and then run res.render() as usual.
app.get('/login', function(res, res) {
res.locals.loggedin = true;
});
app.get('/foo', function(req, res) {
res.render('foo', {});
});