FAQ
Hi.

Imagine a simple route like this:

app.get('/test',
apiCall1(),
apiCall2(),
apiCall3(),
apiCall4(),
apiCall5(),
renderPage()

How would you prevent this code from being executed by the same client
while said client is spamming GET requests (either by refresh page or
clicking buttons, etc.) to the same route ?

I'm using express (+session, static, bodyparser) and have failed to figure
this out on my own.

For example when I first visit /test in the browser, it works fine. But if
I then quickly refresh the page twice in a row, I get to the route twice
for the same session, which in turn doubles the amount of API calls from 5
to 10.

I want it to only occur once, and render the page. I've tried session
variables like "isRequesting true/false" and such, but nothing works,
because the response object changes upon a new request, meaning renderPage
cant use res.send on the "latest" response object.


Cheers.

--
Job board: http://jobs.nodejs.org/
New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
---
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscribe@googlegroups.com.
To post to this group, send email to nodejs@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/cf81af35-399e-4842-8d9d-d8095d54f3bc%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Aria Stewart at Nov 13, 2014 at 7:19 pm

    On Nov 13, 2014, at 12:59 PM, Alex Spencer wrote:

    Hi.

    Imagine a simple route like this:

    app.get('/test',
    apiCall1(),
    apiCall2(),
    apiCall3(),
    apiCall4(),
    apiCall5(),
    renderPage()

    How would you prevent this code from being executed by the same client while said client is spamming GET requests (either by refresh page or clicking buttons, etc.) to the same route ?
    I'd add another middleware at the head of the chain that keeps track of the accesses by a given client (session ID? IP address? Identifying a client can be its own problem, depending!), and errors (with next(an error here)) if the user is over-requesting. Defining that is up to you.


    --
    Job board: http://jobs.nodejs.org/
    New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
    Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
    ---
    You received this message because you are subscribed to the Google Groups "nodejs" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscribe@googlegroups.com.
    To post to this group, send email to nodejs@googlegroups.com.
    To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/D449823A-60EC-42CD-9433-929CFE38AF40%40nbtsc.org.
    For more options, visit https://groups.google.com/d/optout.
  • Alex Spencer at Nov 13, 2014 at 7:38 pm
    But if a user hits Refresh (F5) twice instantly for example, I only want
    the code to run once. But refreshing twice means two response objects. And
    I can only send a valid response to the 2nd created response object. (The
    first one wont work, according to tests) so I can't ignore requests either

    Den torsdagen den 13:e november 2014 kl. 20:19:46 UTC+1 skrev Aria Stewart:

    On Nov 13, 2014, at 12:59 PM, Alex Spencer <alex...@gmail.com
    <javascript:>> wrote:

    Hi.

    Imagine a simple route like this:

    app.get('/test',
    apiCall1(),
    apiCall2(),
    apiCall3(),
    apiCall4(),
    apiCall5(),
    renderPage()

    How would you prevent this code from being executed by the same client
    while said client is spamming GET requests (either by refresh page or
    clicking buttons, etc.) to the same route ?


    I'd add another middleware at the head of the chain that keeps track of
    the accesses by a given client (session ID? IP address? Identifying a
    client can be its own problem, depending!), and errors (with next(an error
    here)) if the user is over-requesting. Defining that is up to you.

    --
    Job board: http://jobs.nodejs.org/
    New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
    Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
    ---
    You received this message because you are subscribed to the Google Groups "nodejs" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscribe@googlegroups.com.
    To post to this group, send email to nodejs@googlegroups.com.
    To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/92e9039c-87e3-4c43-b15a-aa1b9a0cb4e3%40googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Aria Stewart at Nov 13, 2014 at 8:30 pm

    On Nov 13, 2014, at 12:59 PM, Alex Spencer wrote:
    Imagine a simple route like this:

    app.get('/test',
    apiCall1(),
    apiCall2(),
    apiCall3(),
    apiCall4(),
    apiCall5(),
    renderPage()

    How would you prevent this code from being executed by the same client while said client is spamming GET requests (either by refresh page or clicking buttons, etc.) to the same route ?
    Den torsdagen den 13:e november 2014 kl. 20:19:46 UTC+1 skrev Aria Stewart:
    I'd add another middleware at the head of the chain that keeps track of the accesses by a given client (session ID? IP address? Identifying a client can be its own problem, depending!), and errors (with next(an error here)) if the user is over-requesting. Defining that is up to you.
    On Nov 13, 2014, at 2:37 PM, Alex Spencer wrote:
    But if a user hits Refresh (F5) twice instantly for example, I only want the code to run once. But refreshing twice means two response objects. And I can only send a valid response to the 2nd created response object. (The first one wont work, according to tests) so I can't ignore requests either
    Now that is an interesting case, and I think an ideal case for promises: In the first request for a client, create a promise and attach it AND its resolve function to some storage that will outlast the request. If it already exists, don't.

    Call thepromise.then() with the renderPage code.

    Call next() if you set up a new promise.

    Let renderPage resolve that promise instead of rendering.

    var promises = {};
    var resolvers = {};
    function startup(req, res, next) {
         var mainRequest = false;
         if (!promises[req.clientID]) {
             promises[req.clientID] = new Promise(function (resolve, reject) {
                 resolvers[req.clientID] = { resolve: resolve, reject: reject };
                 mainRequest = true;
             });
         }
         promises[req.clientID].then(function (data) {
             // This is where your rendering ACTUALLY goes.
             cleanup();
             res.render(data);
         }).catch(function (err) {
             cleanup();
             res.render('errors');
             // Note that you CAN'T call next(err) here since next has already been called in some branches. c'est la vie. You can work around it but it's ugly.
         });

         if (mainRequest) next();

         function cleanup() {
             delete promises[req.clientID];
             delete resolvers[req.clientID];
         }
    }

    And renderPage:

    functiion renderPage(req, res, next) {
         resolvers[req.clientID].resolve(the data used to render);
    }

    And error handling:

    function errorHandler(req, res, next, err) {
         resolvers[req.clientID].reject(err);
    }

    (that could be in your final apiCall5, but I'd probably factor it separately.)

    What you've now done is joined these requests. They'll all complete when the promise is resolved.

    Aria
  • Matt at Nov 13, 2014 at 10:24 pm

    On Thu, Nov 13, 2014 at 2:37 PM, Alex Spencer wrote:

    But if a user hits Refresh (F5) twice instantly for example, I only want
    the code to run once.

    There's not a system on the planet that will make that work the way you
    want it to.

    Once they hit refresh they have broken the connection to the backend. It's
    not the same connection any more (well it might be under very certain
    circumstances but let's not get into that).

    Now you *might* be able to detect when/if that connection breaks and stop
    processing further API calls (but detecting broken connections isn't always
    trivial), but still you have to run all those API calls for the last
    request.

    Your best (perhaps only) way around this is to use AJAX on the front end
    and have the front-end make those API calls individually to individual
    endpoints.

    --
    Job board: http://jobs.nodejs.org/
    New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
    Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
    ---
    You received this message because you are subscribed to the Google Groups "nodejs" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscribe@googlegroups.com.
    To post to this group, send email to nodejs@googlegroups.com.
    To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/CAPJ5V2YrByawL7b-j9hB%3D454Y%2BdO6XPoXe8yi9%3DG_R%2BixtGo5w%40mail.gmail.com.
    For more options, visit https://groups.google.com/d/optout.
  • Micheil Smith at Nov 28, 2014 at 6:47 pm
    Why can’t your GET request be called multiple times? If it changes data, then you
    should make it a POST/PUT/PATCH request;

    Then with the POST/PUT/PATCH request, you could have an authenticity token
    that you verify is correct before processing any requests. (Which is sort of what
    Aria is suggesting).

    If the route doesn’t change or create data, and simply reads it, then you could set
    up caching for your API Requests.


    However, given your message on 13th November at 7:38 pm UTC, I’d be inclined
    to say that your misusing GET requests if your “creating” things.

    — Micheil
    On 13 Nov 2014, at 5:59 pm, Alex Spencer wrote:

    Hi.

    Imagine a simple route like this:

    app.get('/test',
    apiCall1(),
    apiCall2(),
    apiCall3(),
    apiCall4(),
    apiCall5(),
    renderPage()

    How would you prevent this code from being executed by the same client while said client is spamming GET requests (either by refresh page or clicking buttons, etc.) to the same route ?

    I'm using express (+session, static, bodyparser) and have failed to figure this out on my own.

    For example when I first visit /test in the browser, it works fine. But if I then quickly refresh the page twice in a row, I get to the route twice for the same session, which in turn doubles the amount of API calls from 5 to 10.

    I want it to only occur once, and render the page. I've tried session variables like "isRequesting true/false" and such, but nothing works, because the response object changes upon a new request, meaning renderPage cant use res.send on the "latest" response object.


    Cheers.

    --
    Job board: http://jobs.nodejs.org/
    New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
    Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
    ---
    You received this message because you are subscribed to the Google Groups "nodejs" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscribe@googlegroups.com.
    To post to this group, send email to nodejs@googlegroups.com.
    To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/cf81af35-399e-4842-8d9d-d8095d54f3bc%40googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    Job board: http://jobs.nodejs.org/
    New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
    Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
    ---
    You received this message because you are subscribed to the Google Groups "nodejs" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscribe@googlegroups.com.
    To post to this group, send email to nodejs@googlegroups.com.
    To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/797A3DE8-56EA-4535-86A6-1EE4D0D34080%40brandedcode.com.
    For more options, visit https://groups.google.com/d/optout.
  • Alex Spencer at Dec 1, 2014 at 5:25 am
    I fail to see where I said the GET requests are "creating"/"adding"
    anything, so I apologize if my explanation caused such a confussion.

    The GET requests are merely fetching data. Data which is very likely to
    change more than once an hour, which is why caching isn't an option.

    I've solved the performance issues by pooling the database connections
    instead, and it's working fine now. Although there's still a lot of
    unneccessary resources being used in relation to the database when spamming
    requests like this. That's why I want a decent way to prevent spamming Get
    requests from the same client, same time, same view.

    Den fredagen den 28:e november 2014 kl. 19:47:53 UTC+1 skrev Micheil Smith:
    Why can’t your GET request be called multiple times? If it changes data,
    then you
    should make it a POST/PUT/PATCH request;

    Then with the POST/PUT/PATCH request, you could have an authenticity token
    that you verify is correct before processing any requests. (Which is sort
    of what
    Aria is suggesting).

    If the route doesn’t change or create data, and simply reads it, then you
    could set
    up caching for your API Requests.


    However, given your message on 13th November at 7:38 pm UTC, I’d be
    inclined
    to say that your misusing GET requests if your “creating” things.

    — Micheil

    On 13 Nov 2014, at 5:59 pm, Alex Spencer <alex...@gmail.com <javascript:>>
    wrote:
    Hi.

    Imagine a simple route like this:

    app.get('/test',
    apiCall1(),
    apiCall2(),
    apiCall3(),
    apiCall4(),
    apiCall5(),
    renderPage()

    How would you prevent this code from being executed by the same client
    while said client is spamming GET requests (either by refresh page or
    clicking buttons, etc.) to the same route ?
    I'm using express (+session, static, bodyparser) and have failed to
    figure this out on my own.
    For example when I first visit /test in the browser, it works fine. But
    if I then quickly refresh the page twice in a row, I get to the route twice
    for the same session, which in turn doubles the amount of API calls from 5
    to 10.
    I want it to only occur once, and render the page. I've tried session
    variables like "isRequesting true/false" and such, but nothing works,
    because the response object changes upon a new request, meaning renderPage
    cant use res.send on the "latest" response object.

    Cheers.

    --
    Job board: http://jobs.nodejs.org/
    New group rules:
    https://gist.github.com/othiym23/9886289#file-moderation-policy-md
    Old group rules:
    https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
    ---
    You received this message because you are subscribed to the Google
    Groups "nodejs" group.
    To unsubscribe from this group and stop receiving emails from it, send
    an email to nodejs+un...@googlegroups.com <javascript:>.
    To post to this group, send email to nod...@googlegroups.com
    <javascript:>.
    To view this discussion on the web visit
    https://groups.google.com/d/msgid/nodejs/cf81af35-399e-4842-8d9d-d8095d54f3bc%40googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    Job board: http://jobs.nodejs.org/
    New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
    Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
    ---
    You received this message because you are subscribed to the Google Groups "nodejs" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscribe@googlegroups.com.
    To post to this group, send email to nodejs@googlegroups.com.
    To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/d96d40e0-f164-405c-a224-8d1d1d99b32d%40googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Ryan Schmidt at Dec 1, 2014 at 3:11 pm

    On Nov 30, 2014, at 7:36 AM, Alex Spencer wrote:

    The GET requests are merely fetching data. Data which is very likely to change more than once an hour, which is why caching isn't an option.
    You can, of course, write your code to cache things for any length of time that makes sense for you. It doesn't have to be an hour. Caching for just 5 minutes or even 1 minute would not be noticeable to the user in many cases, and could help performance.


    --
    Job board: http://jobs.nodejs.org/
    New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
    Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
    ---
    You received this message because you are subscribed to the Google Groups "nodejs" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscribe@googlegroups.com.
    To post to this group, send email to nodejs@googlegroups.com.
    To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/2AA854EE-5AFD-45A0-81C5-EABC86B74B86%40ryandesign.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupnodejs @
categoriesnodejs
postedNov 13, '14 at 7:10p
activeDec 1, '14 at 3:11p
posts8
users5
websitenodejs.org
irc#node.js

People

Translate

site design / logo © 2022 Grokbase