This open source chat project https://github.com/meatspaces/meatspace-chat uses the jade index file below. You'll notice that the form has an input value for a #{csrf} token. Where would this csrf value be coming from? Is it part of the browser environment? I don't see any javascript in the project that inserts that csrf token into that input field.
For example, when you visit the root, it just renders the index like this
app.get('/', function (req, res) {
res.render('index');
});
index
extend layout
block content
form(method='post', id='add-chat-form')
input(type='hidden', name='picture', id='picture')
.message-content
input(name='message', id='add-chat', class='input', maxlength='250', autocomplete='off', placeholder='Send a public message')
input(type='hidden', name='_csrf', value='#{csrf}')
input(type='hidden', name='fingerprint', id='fp')
input(type='hidden', name='userid', id='userid')
#add-chat-blocker.hidden
span Sending, please wait!
#counter 250
The tokens are created by the connect csrf middleware. You can see this in settings.js. On line 7:
var csrf = express.csrf();
and line 13:
var clientBypassCSRF = function (req, res, next) {
if (req.body.apiKey && nativeClients.indexOf(req.body.apiKey) > -1) {
next();
} else {
csrf(req, res, next);
}
};
This exposes a function csrfToken on the req object, which is used on line 45:
res.locals.csrf = req.csrfToken();
The express templating engine (res.render('index'); in the code you showed in your question) extends the templates scope with the res.locals object, which is how that field gets filled in during templating.
Related
I have created a rest api in nodejs
i have the get request function like this:
server.js
const search = 'example' //user input search variable changes based on input from html file
app.get('/api/getData', (req, res) => {
var url = 'externalapiurl' + search // so you can see that my requests depends on the users input search variable
request(url, function (err, response, body) {
var data = 'json loaded data'
res.send(data)
});
});
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
})
i also have a html file and another script.js that has a search button where the user can type in a string and that string i want it to be the 'const search' in the server.js and then after that to return it back to the html file just to test it.
index.html script.js server.js script.js index.html
----search----- ----> puts string into const search ----> send back to html and display as text
this might help with the html search button
server.js
const searchbtn = document.getElementsByClassName("search-btn")[0];
searchbtn.addEventListener("click", getAns);
function getAns() {
var search = document.getElementById("input").value;
//what do i do now?
}
how do i call the get function to my api from my script.js file, taking subreddit variable with it into server.js and then sending it back to html file.
I'm working on a SPA website with node.js, jQuery, mongoose and MongoDB for a shopping website.
The ajax requests and responses work perfectly when starting from the index.html file. So for example begining on http://localhost:3000 and someone clicks on a link called 'products' I send an ajax request to the the server and the server sends the necessary product information back asynchronously which lead to http://localhost:3000/products. But the problem is that if someone types http://localhost:3000/products directly in the search bar it will show the json representation of the products.
This is my code:
script.js
function redirect (link) {
$.ajax({
type: 'GET',
url: 'http://localhost:3000/' + link,
contentType: 'application/json',
data: {
link
},
success: function (res) {
let container = $('#contentToSwap');
container.html('');
res.products.forEach(function (products_) {
...
});
}
});
}
app.js
var Product = require('./models/product');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var path = require('path');
var express = require('express');
var app = express();
mongoose.connect('mongodb://localhost:27017/shopping');
var PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.get('*', function(req, res) {
Product.find(function(err, docs) {
let productChunks = [];
let chunksize = 4;
let display = [];
for (var i = 0; i < docs.length; i++) {
if (docs[i].productType == req.query.link) display.push(docs[i]);
}
for (var i = 0; i < display.length; i += chunksize) {
productChunks.push(display.slice(i, i + chunksize));
}
res.send({ products: productChunks });
});
});
app.listen(PORT, function () {
console.log('Listening on port ' + PORT);
});
So I need some sort of frontend routing if the user doesn't start at the index.html file. I know that I could write my own router to route the urls correctly and that I could route all requests back to the index.html like
app.get('*', function(req, res) {
res.sendFile(__dirname + '/public/index.html');
});
But then I cannot load all the necessary product information from the server when someone clicks a link. So I'm a little bit confused on hwo to tackle this issue. Any help is appreciated
This is usually achieved by separating api routes from normal ones by adding specific url prefixes such as /api for all routes that return json data. What you can do is to specify /api/whatever-you-want, make it the target for your ajax call and place it above app.get('*' ....
Since routes and middleware functions are resolved top to bottom, it will be matched by your ajax call only, leaving the /products unaffected.
answer to question -- Is it possible to redirect user from /api/products to /product if the request wasn't generated by ajax?
Yes, it is possible by adding request query parameter to ajax call which will not be present on normal call and then check those on the server side and decided what to do if it (that specific query parameter) is missing or not.
Let's assume some client side JS that generates ajax call.
fetch('/api/products?api=true')
.then((data) => data.json())
.then((json) => console.log(json));
Notice the request url - /api/products?api=true
Now assume a normal call from html file.
products
These two calls differ in that api query parameter (ajax call has it, the other one doesn't).
And for the server side part of the task -- request query parameters object can be accessed via query property on request object (req.query).
app.get('/api/products', (req, res) => {
if (!req.query.api) {
// if get request doesn't contain api param. then
// handle it accordingly, e.g. do redirect
return res.redirect('/products');
}
// request comming from ajax call, send JSON data back
res.json({ randomStuff: 'abcd' });
});
I have been creating a website with Mean stack and I stuck at some point. I have a mongo db database and I am currently getting each file from database (to show them on Main page) with my Rest Api which is build with Express.
Server.js
var express = require('express');
var app = express();
var mongojs = require('mongojs');
var db = mongojs('mongodb://username...', ['myApp']);
var bodyParser = require('body-parser');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json());
app.get('/myApp', function (req, res) {
db.myApp.find(function (err, docs) {
console.log(docs);
res.json(docs);
});
});
app.get('/myApp/:id', function (req, res) {
var id = req.params.id;
console.log(id);
db.myApp.findOne({_id: mongojs.ObjectId(id)}, function (err, doc) {
res.json(doc);
})
});
app.listen(3001);
console.log('Server running on port 3001');
There is 2 get method and I can understand that because they have different parameters. So when I call them from controllers, there is no problem because if I provide id, it will call the second get method. But for example I want to use something like this in my website;
app.get('/myApp', function (req, res) {
db.myApp.find({}).limit(2).skip(0, function(err, docs) {
console.log(docs);
res.json(docs);
});
});
This get method have no parameter like the first get method in server.js but they do different jobs. This is limiting my search with 2 file. How can I use different get methods like this in my Mean Stack application?
This is my code for calling get method from my main controller. How can I make sure to call specific get method? Thanks..
$http.get('/myApp').success(function(response) { .. });
What you want is not possible. Somehow you need to distinguish between your 2 intentions, either by giving the endpoints different names (like you already suggest in your comment) or by providing for example a query parameter so you could do a call like:
$http.get('/myApp?limit=2').success(function(response) { .. });
When limit is omitted, you could return all results.
Something like:
app.get('/myApp', function (req, res) {
var limit = req.query.limit;
if (limit === undefined) {
// Return everything
} else {
// make sure limit is some valid number
// ... and do a mongo query limited to this number
}
});
I have a middleware that rewrites the request.url. However in the next() middleware, the request.url is still the original unmodified url.
Example:
var express = require('express');
var router = express.Router();
router.use(function(req, res, next) {
console.log('Before Rewrite',req.url);
if(/^\/v[1-9]/.test(req.originalUrl) ) {
console.log('Rewritten');
req.url = '/api' + req.originalUrl;
}
console.log('After Rewrite',req.url);
next();
});
router.use('/api', function(req, res, next) {
console.log('Next', req.url);
next();
});
With an example url of '/v3/foo' the following is output to console:
Before Rewrite /v3/foo
Rewritten
After Rewrite /api/v3/foo
Next /v3/foo
Any thoughts on why the request changes do not persist on to the next middleware?
Thanks to the link from #kelz to the Express next() code, I have a better understanding of how Express handles urls. It seems that req.url is writeable because Express removes the root of the url when matching. For example with an original url of '/foo/bar', if you have this:
router.use('/foo', someMiddleWare);
Then req.url within someMiddleWare will now be '/bar' i.e. with the matched root removed. This is why we have req.originalUrl (which is not writeable) to persist the unaltered url.
As my original approach to rewriting the url can't work, I opted for a simpler solution:
router.all(/^\/v[1-9]/, function(req, res) { res.redirect('/api' + req.originalUrl); });
This way, after the redirect, the req.originalUrl is as it should be for my later middleware.
You are not sharing the same object in both functions. The moment you change the value of req in the middleware function the scope is bound only inside that function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Example:
function doAThing(a) {
a = 5;
return;
}
var n = 4;
doAThing(n);
console.log(n); // 4
I have a page with a route GET /team which is loading a list of teams, and DEL /team which is deleting a team from /team/:key. So you navigate to a team's profile page and delete them from there, on deletion it should redirect you to the /team page. I have put logs into the console and it is successfully deleting the team and wierdly, it says it is loading /team but the browser does not load this. I have put my code below, any ideas?
Routes:
app.get('/team'/*, lim("Must be logged in to see teams")*/, getAllTeams, function(req, res){
util.log('Serving request for url [GET] ' + req.route.path);
// Pass it the list of all Teams
res.render('team', {'teamsList' : req.teamsList} );
});
app.get('/team/:key', function(req, res) {
util.log('Serving request for url [GET] ' + req.route.path);
Team.findByKey(req.params.key, function(err, teamData){
if(!err && teamData){
teamData = teamData;
res.render('teamDetails', { 'teamData' : teamData } );
} else {
util.log('Error in fetching Team by key : ' + req.params.key);
res.json({
'retStatus' : 'failure',
'msg' : 'Error in fetching Team by key ' + req.params.key
});
}
});
});
/**
* DEL /team/:key
* Delete Team by key
*/
app.del('/team/:key', getAllTeams, function(req, res) {
util.log('Serving request for url [DEL] ' + req.route.path);
Team.remove({key : req.params.key}, function(err){
var message = '';
var retStatus = '';
if (!err) {
util.log('Successfully deleting Team with key: ' + req.params.key);
message = 'Successfully deleting Team with key: ' + req.params.key;
retStatus = 'Success';
res.redirect('/team');
} else {
util.log('Error deleting Team with key: ' + req.params.key + 'Error: ' + util.inspect(err));
res.json({
'retStatus' : 'failure',
'msg' : 'Error in fetching Team with key ' + req.params.key
});
}
});
});
JavaScript + HTML template:
button#teamDelete.btn.btn-danger.btn-mini(type="submit", value="Delete Team") Delete
script(type='text/javascript')
$('#teamDelete').live('click',function(){
var teamId = #{teamData.key};
$.post('/team/' + teamId, { _method : 'delete' }, function(response) {
console.log(response);
if(response.retStatus === 'Success') {
if('/team' && '/team' !== "") {
window.location = '/team';
}
}
});
});
console logs:
10 Mar 11:52:01 - Serving request for url [GET] /team
10 Mar 11:52:02 - Serving request for url [GET] /team/:key
10 Mar 11:52:03 - Serving request for url [DEL] /team/:key
10 Mar 11:52:03 - Successfully deleting Team with key: 1362855941128
10 Mar 11:52:03 - Serving request for url [GET] /team
getAllTeams:
var getAllTeams = function(req, res, next){
Team.getAll(function(err, teamsList){
if(!err && teamsList){
req.teamsList = teamsList;
return next();
}
});
};
Team.getAll (Team schema)
Team.statics.getAll = function(cb){
var query = this.find({});
query.sort({key : -1});
return query.exec(cb);
};
Your request is POST ($.post) and you route is app.del, so it never gets to res.redirect inside app.del route.
Why don't you use app.post?
Updated:
Assuming $.post sends HTTP DEL request here what is happening: server sends 302 response with no data but browser never sends another request to GET route as server instructs it (or does jQuery handle redirects too? Not sure). res.redirect() is actual HTTP response not some internal server-side instruction to re-route the request to another route like you can do in ASP.NET (and which is wrong actually)... Route is designed to receive request, reply with the response and forget about it. You need to separate routes from actual functions processing them, then you will be able to call that function instead of sending redirect.
Code suggestions
In app.del('/team/:key' ...
...
retStatus = 'Success';
// res.redirect('/team');
res.send({
retStatus : retStatus,
redirectTo: '/team',
msg : 'Just go there please' // this should help
});
...
Client-side in $.post('/team/' ...
...
$.post('/team/' + teamId, { _method : 'delete' }, function(response) {
console.log(response);
if(response.retStatus === 'Success') {
// not sure what did you mean by ('/team' && '/team' !== "")
// if('/team' && '/team' !== "") {
if (response.redirectTo && response.msg == 'Just go there please') {
window.location = response.redirectTo;
}
}
});
...
Not sure it will work though because I don't understand what your getAllTeams does and why you store teamList in req. If you want to store in session, than assuming the middleware is correctly configured you need to use req.session. If you need to store it only within request and your getAllTeams prepares this list of teams it is better to store in res.locals (like res.locals.teamList).
And make sure your getAllTeams calls next. So basically your getAllTeams should look like this:
function getAllTeams (req, res, next) {
res.locals.teamList = [/* whatever */];
next();
}
And then you can use res.locals.teamList in your route handler instead of req.teamList.
res.render('team', {teamsList : res.locals.teamsList} );
And 'team' template also can have a problem...
Express advice :)
Also the way you use Express makes it very difficult to extend/manage application. I don't remember where exactly, but somewhere in docs they write that Express is supposed to be used as the foundation for your application framework, not as a complete framework like most PHP frameworks are. It gives you a lot of power and flexibility, but also makes it necessary to think about your application architecture well in advance.
The most powerful feature of express is that you can have any route handled by many route-specific handlers/middlewares passing control to each other via next(). I have a static table that defines which handlers are used on each route allowing to see the whole application with 30 or so routes on one page. And this table is used to assemble the routing dynamically when the application starts. It leads to a lot of flexibility, manageability (I can move/copy-paste handlers from route to route - each handler is represented as a single word) and code re-use. I also use the same hash of routes definition in the client for client-side routing.
For a quick workaround, just add the redirect url to the response and on the client side do:
if (redirectUrl && redirectUrl !== "")
window.location = redirectUrl;