I have a script that plays music and because of the nature of the script it seems to be running 2 connections for every 1 listener.
What that means is it is creating 2 documents inside Mongodb.
I am wondering is there a way to tell mongoose to not insert document within 5 seconds if the insert has already ran?
I have run a console.log(req.url)
and I get the following
/dance?uuid=6f70c645-4ef4-4042-854d-a6e87b61e45f
/dance?uuid=6f70c645-4ef4-4042-854d-a6e87b61e45f
Which means it is requesting the file twice on load.
Is there away to only allow 1 request to go through and discard the other?
I have tried
router.get('/:stationname', (req, res, next) => {
console.log(req.url)
});
Also tried the following
var doCSUpdateAlreadyCalled = false;
router.get('/:stationname', (req, res, next) => {
if (!doCSUpdateAlreadyCalled) {
doCSUpdateAlreadyCalled = true
console.log(req.url)
}
});
But it still runs twice.
Related
I'm quite new to NodeJS, and I came across a construction that I can't wrap my head around. Consider the following code:
router.get("/", function(req, res, next) {
let db = new sqlite3.Database(dbname, sqlite3.OPEN_READONLY, (err) => {
if (err) next(err);
});
res.render("views/page");
}
If an exception is raised by Database (for instance because dbname does not exist), then the callback will pass it to the Express error handler (next). But the code does not stop there, and it will continue to execute the next line and attempt to render something, which is problematic if the error handler also sends headers. If I add a return statement within the callback, it will simply terminate Database but not the rest of the function.
My question: is there anyway to prevent the rest of the code from being executed if an exception is raised?
Please read the sqlite3 npm documentation. Ideally, you should not be opening a database connection on every request. Instead, you should open the database connection when the server is started, and share a reference to the db variable to be used in the API routes (gets/posts).
Unless you just want to make it work, I believe the below should do it.
router.get("/", function(req, res, next) {
let db = new sqlite3.Database(dbname, sqlite3.OPEN_READONLY, (err) => {
if (err) return next(err);
res.render("views/page");
});
}
EDIT: Javascript does not allow for async/await when instantiating objects, so in this case I believe would be better to just initialize the database connection outside the router method, like below, and use the error event to handle errors
const db = new sqlite3.Database(dbname, sqlite3.OPEN_READONLY);
db.on('error', function(err) { /*handle error here*/ });
router.get("/", function(req, res, next) {
res.render("views/page");
});
}
How to run function within a function
If the first function throw any error then 2nd function should run
server.post('/User', (req, res,next) =>
server.post('/submit', (req, res) =>
server.post('/User', (req, res,next) => {
// Some Task
if(){
//Do something
}
else {
server.post('/submit', (req, res) => {
If the first function returns a promise you could run those functions after catching the error like this:
firstFunction()
.catch(e => {
secondFunction();
});
Otherwise you could use a try-catch statement like this:
try {
firstFunction();
} catch (e) {
secondFunction();
}
In Express, the next parameter allows a route/middleware to pass processing to the next route/middleware (actually, all routes are merely middlewares that don't call next). Therefore you can implement passing your route processing by just calling next():
function submitHandler (req, res) {
// ...
}
server.post('/User',
(req, res, next) => {
if(/* all ok */){
//Do something
}
else {
next(); // continue processing
return;
}
},
submitHandler // continue with this function
)
server.post('/submit', submitHandler); // also have a separate endpoint where
// submitHandler can be accessed directly
Remember that server.post(...) doesn't actually carry out that operation in that route. It just registers a route handler for some future route. So, you don't generally do things like:
server.post("/firstRoute", function(req, res, next) {
if (some condition) {
server.post("/secondRoute", ...);
}
});
This would configure a second route handler for all users based on what one user did in their /firstRoute request.
Remember a server contains a set of route handlers that work for ALL users that will use the server now and in the future. What your code proposes is that based on some data in one particular incoming request, you would change the routes that the server supports for all users. That's not how you would code a server.
If you need to maintain server-side state for a particular user such that data from one request influences how some future request works, then you would typically create a user session object, store the state for that user in the session and then one some future request, you can consult the data in the session to help you respond to the future request.
A simple example would be a shopping cart. Each time you add something to the cart, the data is added to the session object. Then, when the user asks to view the cart, you render a page by consulting the items in that user's session object. If they then ask to "check out", you purchase the items in the cart for them. You don't register and deregister routes for "view cart" and "checkout". Those routes are always registered. Instead, you use the data in the session object to help you process those requests.
If you want to run the same code from several different routes, then you just move that code into a shared function and call that shared function from more than one route handler.
So I'm writing an application in node.js+express which I want to achieve the following goal.
User POST many requests at a nearly same time (like with command curl...& which & makes it run at the background)
Process each request at one time, hold other requests before one is finished. The order can be determined by request arrive time, if same then choose randomly. So if I POST 5 requests to add things in the database at nearly the same time, the first request will be added into database first, while other requests will be held (not responding anything yet) until the first request is been processed and respond with a 200 code then follow on processing the second request.
Is it possible to achieve this with express, so when I send couple requests at one time, it won't occur issue like something isn't add into MongoDB properly.
You can set up middleware before/after your routes to queue up and dequeue requests if one is in progress. As people have mentioned this is not really best practice, but this is a way to do it within a single process (will not work for serverless models)
const queue = [];
const inprogress = null;
app.use((req, res, next) => {
if (inprogress) {
queue.push({req, res, next})
} else {
inprogress = res;
}
})
app.get('/your-route', (req, res, next) => {
// run your code
res.json({ some: 'payload' })
next();
})
app.use((req, res, next) => {
inprogress = null;
if (queue.length > 0) {
const queued = queue.shift();
inprogress = queued.res;
queued.next();
}
next();
})
app.route('/users')
.post(user.post)
.get(user.get)
.get(user.everyone)
.put(user.update)
.delete(user.delete);
I have ran into the problem of my function using two res.send, so I am getting the 'Error: cannot set header after they are sent.' error, to fix this I have turned it into two functions which I am trying to use two .get on the app.route, but it seems I can only use one as when I use two the second one doesn't work.
Is there a way I could use two .get on one app.route?
If not, what are my options to get around this problem?
You need to create separate routes for each api endpoint like this:
app.route('/users').get(req, res) => {
//Get all users
});
app.route('/users:/id').get(req, res) => {
//Get specific user
});
app.route('/users').post(req, res) => {
//Create new user
});
app.route('/users/:id').put(req, res) => {
//Update user
});
app.route('/users/:id').delete(req, res) => {
//Delete user
});
Once res.send is called, means your server has sent the response to the browser or whatever. you can't change the already sent response and its header.
You can use multiple callbacks on one route and one method(post,get)
An array of callback functions can handle a route. For example:
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
var cb2 = function (req, res) {
res.send('Hello from C!')
}
app.get('/example/c', [cb0, cb1, cb2])
yes, you can use multiple HTTP requests either its .get or .post but with different params. or routes.
In the following test code req.query is checked to see if its value is name=cat. If this is not true next() fires off the next piece of middleware. This is accomplished without including a return statement after next() and it works as expected.
app.get('/test', (req, res, next) => {
if (req.query.name != 'cat') {
next();
}
res.send('it was cat');
});
app.get('/test', (req, res) => {
res.send('it was not cat');
});
However when I change res.send to res.sendFile in the second piece of middleware the behavior is completely different.
app.get('/test', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});
After the change res.send('it was cat'); in the first piece of middleware fires every time, regardless of the value of name. In addition the second piece of middleware never fires.
This can easily be fixed by adding a return after next() in the first piece of middleware. The behavior becomes predictable again.
app.get('/test', (req, res, next) => {
if (req.query.name != 'cat') {
next();
return;
}
res.send('it was cat');
});
app.get('/test', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});
Why does this happen with and without the return statement? A return is needed when I use res.sendFile but not when I use res.send. I'm sure I'm missing something obvious but I don't understand the pattern.
This is accomplished without including a return statement after next() and it works as expected.
No, it looks like it works as expected, but it doesn't. For instance, if you retrieve /test without query parameter, or with a query parameter that doesn't equal name=cat, Express will log an error:
Error: Can't set headers after they are sent.
I cannot reproduce your second example; for me, it always returns "it was cat" (in the example without return).
The common rule for any Express handler/middleware is: it should either end the response itself (by calling res.end, res.send, res.render, res.sendFile, etc) or pass the request along using next. In your case, without return, you're doing both. The result of that will be, practically speaking, undefined.
When your listener performs res.send('it was not cat') the entire processing of the request takes place without hitting the trampoline. The next() call never completes until after res.send('it was not cat') finishes. So by the time the code for send('it was the cat') is reached, the response is already sent.
But when your listener performs res.sendFile() the processing of the response is asynchronous. The file has to be read into memory, which is non-blocking I/O in Node. The callback for that I/O is placed into the event queue, and then processing continues. So the next() call returns and then send('it was the cat') executes. All this is before the file is even read into memory. Later when the file is read, the code dutifully attempts to send the response, but it's too late.