I'm getting around to using domains and am trying a couple of Express domain middleware packages:
https://github.com/brianc/node-domain-middleware
https://github.com/baryshev/connect-domain
According to the usage docs on the first one I should have access to process.domain but it is undefined.
I am basically doing this in my app.js
var express = require('express'),
domains = require('express-domain-middleware');
var app = exports.app = express();
app.use(domains);
And in a controller:
exports.index = function(req, res, next) {
console.log(process.domain); //undefined
};
What gives?
You might want to check (using console.log or breakpoints) to make sure this line is happening before your index method is getting called:
express.use(domain);
I don't know how your app is structured but order of app.use is usually the case.
Your app.get('/someurl', yourcontroller.index) should come after app.use(domain).
Ok - it's due to a Mongo call in my middleware. Evidently all database calls have to be wrapped.
var d = domain.create();
d.run(function () {
client.query('...', d.intercept(function (rows) {
// ... use rows (note, first arguments error was "intercepted" by the domain)
}));
});
Reference: https://github.com/felixge/node-mysql/issues/308
Related
The Problem occurs while sending GET or any request with parameters in the URL.
for example my
index.js
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/:name", function (req, res) {
let name = req.params.name;
console.log("Hello " + name + " from /:name");
res.send("Hello " + name + " from /:name");
});
app.get("/", function (req, res) {
console.log("Hello world from /");
res.send("Hello world from /");
});
app.listen(3000, () => {
console.log("Server is running on port " + 3000)
});
For http://localhost:3000/ it's working perfectly fine.
the Problem is occurring when we try to hit /:name route
when we use URL http://localhost:3000/?name=NODE it is going to the same route as above. in /
But the crazy part is when we put http://localhost:3000/NODE which is simply a new different route that is not implemented.
It is getting the response from :/name which doesn't make any sense.
is it a BUG or I am doing something wrong or is it something new I am not aware of?
I am currently using Windows11,
this problem also occurs in my friend's PC who uses Ubuntu
When you define route as
/:name
That's called path parameter and it's used like this :
GET /yourname
And that's why this works :
GET /NODE
What you"re using to call the endpoint (?name=xxx) is called query parameter, you can get that name from '/' endpoint like this :
let name = req.query.name;
I think you're almost there, but /:name does not match /?name=, but it does match /NODE.
This is exactly what's expected to happen. If this surprised you, go re-read the documentation because it should be pretty clear on this.
I think I am confused between query parameters and params.
Let:
given this URL http://www.localhost:3000/NODE?a=Debasish&b=Biswas
We will have:
req.query
{
a: 'Debasish',
b: 'Biswas'
}
req.params
{
param1: 'NODE'
}
Here I am sending a query but want to receive params. That is where I go wrong.
For better understanding check :
Node.js: Difference between req.query[] and req.params
So I'm not really sure if the title is descriptive enough, but here is a super simple example.
My site has a public area and a restricted admin area.
example.com/admin (admin home page)
example.com/admin/news (news page)
example.com/admin/posts (posts page)
And because I don't want people who aren't administrators or logged in to be able to access it, I have a simple middleware function to check for cookies.
app.js
const express = require('express');
const app = express();
const authMiddleWere = async (req, res, next) => {
// pseudo-code, do some cookie validity check here
console.log(`Route: ${req.url}`)
if (cookie) {
next();
}
};
const adminRouter = require('./routes/private/home');
const newsRouter = require('./routes/private/news');
const postsRouter = require('./routes/private/posts');
app.use('/admin/', authMiddleWere, adminRouter);
app.use('/admin/news', authMiddleWere, newsRouter);
app.use('/admin/posts', authMiddleWere, postsRouter);
/routes/private/home.js
const express = require('express');
const router = express.Router();
router.get('/', async (req, res, err) => {
res.render('private/home');
});
module.exports = router;
The problem here is that this authMiddleWere function gets called twice when I visit nested paths such as example.com/admin/news which shares the same pattern - it's starting with /admin/......
I can tell that for sure because we are logging the req.url in our middleware function so if I go to example.com/admin it will log out:
Route: /
But if I go to example.com/admin/news it will log out both:
Route: /
Route: /news
So what is causing this and how do I work my way around it? I'm assuming that what I described is the intended behavior of Express.js so I am looking for a way to get around this or (re)structure my code better.
Cheers!
You can use a regex for your route.
app.use(/\/admin$/, authMiddlewear, authRouter);
This will match only routes that end in admin. You may need to handle cases where the route is /admin/ instead of /admin, but iirc, express handles that intelligently.
Well one way you can fix this is by creating a separate route file and splitting everything into a MVC manner. For example:
Inside your main app.js just create a route pointing to the /admin like so:
app.use('/admin', authMiddleWere, require('./src/your-route-to-the-file/admin.route'));
Inside the admin.route file, call your controller like this:
const express = require("express");
const router = express.Router();
const mainAdminCtrl = require("../controllers/admin.controller");
router.get("/news", mainAdminCtrl.adminAuthDisplay);
module.exports = router;
Where the const mainAdminCtrl is your controller and the function adminAuthDisplay is your service.
Essentially, you are splitting your functionality in to a dedicated router, controller and service file. So when you try to access the route /admin, it will look for any suffix inside the router file.
In a case where you want to access the /news endpoint, your API will only make the call once.
If this helps, I can expand my explanation further.
I have a bit of an issue when i try to create an object prototype in my node/express app.
I first start by creating the prototype like so:
Object.prototype.printObject = function () {
return console.log(this);
}
Now the issue is when I call this function. For instance when i call the function like this:
let request = {1:2}
request.printObject();
*//Logs {1:2}*
No error occurs. Yet when I call the function like this:
let request = req.body
request.printObject();
My program crashes with error: TypeError: request.printObject is not a function
Does anyone have any clue as to why this occurs?
if you require('body-parser')? or req.body is undefined,you should do this first
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
You have added the 'printObject' method on the prototype of Object. So if req.body is an Object, you should be able to call the method.
Try checking the type of req.body using console.log(typeof req.body) to verify that it is an Object.
If it is not, you should use the node module 'body-parser' to populate req.body with the parsed body content.
For example, parts of your server code might look like this:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json()); // Data is being sent to the server in JSON format
app.post('/my/endpoint', function(req, res){
req.body.printObject();
});
The 'body-parser' module supports other formats as well. I used JSON as an example. You can find everything they support here: https://www.npmjs.com/package/body-parser
Insteat of trying to prototype any Object, you could create a middleware function like so:
app.use(function (req, res, next) {
console.log('req');
//you could also add any function to req,even so thats not a common thing to do
req.printObject = function { ... }
next();
});
Probably the problem with your approach is, that you add the function to the Object prototype after the request object was created.(EDIT: This is wrong, see comments)
Being a newbie in Nodejs, I jumped right into writing a simple app without really reading up on good security practices. I just found out that using bodyParser() for all routes is actually a bad thing because it allows for DOS attack using multipart files.
A recommended fix is to only load specific modules depending on the route. ie, for multipart fileupload, use multipart. For regular POST without file uploads (ie, text form submission), use express.json(), express.urlencoded().
Or another option is to use busboy with connect-busboy. But the thing I'm confused on is how I can specify which route should handle multipart data and which should not? Otherwise, wouldn't I have the same problem as with bodyParser?
Furthermore, busboy docs says it does not handle GET:
If you find that req.busboy is not defined in your code when you expect it to be, check that the following conditions are met. If they are not, req.busboy won't be defined:
1. The request method is not GET or HEAD
So, I'm even more confused how I would parse params in a GET. I think bodyParser does this for me so I could access data with req.params.
For example, how would I migrate away from bodyParser() to busboy/connect-busboy with this simple app:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
app.use(bodyParser.json());
var busboy = require('connect-busboy');
app.use(busboy());
// How to use busboy to prevent multipart files here?
app.post("/form_data_no_fileupload", function(req, res) {
var somedata = req.body.somedata;
});
// Use busboy to handle both regular form data + fileuploads
app.post("/form_data_AND_fileupload", function(req, res) {
});
// What would handle GET without bodyparser?
app.get("/get_something", function(req, res) {
var params = req.params;
});
http.listen(3000, function() {});
[How] I can specify which route should handle multipart data and which should not?
All of Express' routing methods allow for providing middleware specific to the route. This includes Router methods.
app.METHOD(path, callback [, callback ...])
Depending on the body expected for an individual route, you can use different modules to handle each of them (rather than applying them to the entire application with app.use()).
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
var busboy = require('connect-busboy');
app.post("/form_data_no_fileupload",
bodyParser.urlencoded(),
function(req, res, next) {
// check that the request's body was as expected
if (!req.body) return next('route'); // or next(new Error('...'));
// ...
});
app.post("/form_data_AND_fileupload",
busboy({
limits: {
fileSize: 10 * 1024 * 1024
}
}),
function(req, res, next) {
// check that the request's body was as expected
if (!req.busboy) return next('route'); // or next(new Error('...'));
// ...
});
// ...
Furthermore, busboy docs says it does not handle GET.
So, I'm even more confused how I would parse params in a GET.
Busboy and BodyParser are designed for reading in and parsing the request's body, which GET and HEAD requests aren't expected to have.
For such requests, parameters can only be passed within the query-string within the URL, which Express parses itself. They're available via req.query.
app.get('/get_something', function () {
console.log(req.originalUrl);
// "/get_something?id=1
console.log(req.query);
// { id: "1" }
});
req.params represents any placeholders matched in the path by the route. These are available for any route, regardless of the method.
app.get('/thing/:id', function (req, res) {
console.log(req.originalUrl);
// "/thing/2"
console.log(req.params);
// { id: "2" }
});
I'm creating a simple testing platform for an app and have the following code setup as my server.js file in the root of my app:
var restify = require('restify'),
nstatic = require('node-static'),
fs = require('fs'),
data = __dirname + '/data.json',
server = restify.createServer();
// Serve static files
var file = new nstatic.Server('');
server.get(/^\/.*/, function(req, res, next) {
file.serve(req, res, next);
});
// Process GET
server.get('/api/:id', function(req, res) {
// NEVER FIRES
});
It serves static files perfectly, however, when I try to make a call to the /api it just hangs and times out. Imagine I'm missing something stupid here, any help would be greatly appreciated.
node-static is calling next with an error, which means it's never yielding to other handlers.
You can move your other handlers above node-static or ignore it's errors by intercepting it's callback.
I made a working version here: http://runnable.com/UWXHRONG7r1zAADe
You may make yourself sure the api get call is caught by moving the second get before the first. The reason is your api calls routes are already matched by the first pattern.