nginx/njs

How to implement an external rate limitter?

Closed this issue · 2 comments

I would like to implement a rate limitter, but externally, to be shared between multiple nginx servers.
I already have a service that attends on my POST http://localhost:3000/verify_limits address, which expects a body like below:

{
    "uri": "/address/of/this/call",
    "orgId" : "xxxxbxa-4a47-4176-b85e-8dbb2f2938a6",
    "token": "content of authorization header"
}

uri: The address that the client is calling (r.uri)
orgId: A client certificate attribute extracted from subject. I think I can get this value using r.variables.ssl_client_raw_cert variables, as documented here.
token: The authorization header. I think I can get this value through r.headersIn.Authorization.

As result, it returns the http codes 429, 423 or 200.

Now, I would like to implement an script that when the address "/address/of/this/call" is called, first the njs script needs to call http://localhost:3000/verify_limits and based on it's response (http status code), redirect to another proxy_pass in case of http status code 200 or return 429 or 423.

I've tried to use ngx.fetch on my script, but when using it I always receive and http 500 code from nginx, as if ngx.fetch, even with a very simple code like below:

async function authorize(r) {
    let reply = await ngx.fetch("http://localhost:3000/validate_limits", {
        method: "POST",
        body: { "uri": r.uri, "orgId" : "xxxxbxa-4a47-4176-b85e-8dbb2f2938a6", "token":  r.headersIn.Authorization}
    });
    r.return(200);
}

export default {authorize}

I really appreciate any help.
Thanks

Hi @ranierimazili,

Please make sure that nginx.fetch() receives a body property as a string, using JSON.stringify({{ "uri": r.uri, "orgId" : "xxxxbxa-4a47-4176-b85e-8dbb2f2938a6", "token": r.headersIn.Authorization})
ngx.fetch() converts "body" using ]toString()method, and for objectstoString()` returns the following text "[object Object]".

Thanks for your help...
I've found the reason of my problem... I was using http://localhost:3000 and for some reason nginx was resolving localhost to an ipv6 address... replace to 127.0.0.1 solved the problem and now it's requesting my local service.