njs: If two or more "location" block defines the same "js_var" directive name, the value will be overwritten

Abstract:

If two or more “location” block defines the same “js_var” directive name, the value in the previous “location” block will be overwritten by the next “location” block. This behaviour is not the same as the “set” directive, it should be consider as a bug.


Detail:

js_content directive can pass “module.function” which only accept one paramter (r: NginxHTTPRequest), but sometimes developer want to pass more paramters by location block with same “module.function”. js_var or set may be used as this idea.

The problem is, when use the same name in js_var, the last one will overwrite the previous one. that means value isolation by location block fail.

This behavior does not exist in the “set” directive, so it should be consider as a bug.


Environment & Version:

CentOS 7 nginx.x86_64 1:1.25.2-1.el7.ngx nginx-module-njs.x86_64 1:1.25.2+0.8.0-1.el7.ngx


Steps to reproduce:

nginx.conf:

server {
    listen       8765;
    server_name  localhost;
    

    js_import test from test.js;

    location /test {
        js_var $js_var_test "js_var_test from /test";
        set $set_test "set_test from /test";
        js_content test.test;
    }

    location /test2 {
        js_var $js_var_test "js_var_test from /test2";
        set $set_test "set_test from /test2";
        js_content test.test;
    }

}

test.js:

function test(r){
    r.return(200, JSON.stringify({
        "js_var_test": r.variables.js_var_test,
        "set_test": r.variables.set_test
    }));
}


export default {test};

curl /test:

curl -v "http://localhost:8765/test" curl /test2:

curl -v "http://localhost:8765/test2"


What is expected?

Started from “from” string, the value from js_var_test should be the same as set_test.


What is actually happening?

curl /test:

{"js_var_test":"js_var_test from /test2","set_test":"set_test from /test"} (js_var_test is overwritten)

curl /test2:

{"js_var_test":"js_var_test from /test2","set_test":"set_test from /test2"}

About this issue

  • Original URL
  • State: closed
  • Created 10 months ago
  • Comments: 15 (3 by maintainers)

Most upvoted comments

@salacr please try using = with the error_page directive with one of these:

error_page 500 =503 @process_error_500; # Override the status code directly
error_page 500 = @process_error_500;    # Delegate setting the status code to the named location

https://nginx.org/en/docs/http/ngx_http_core_module.html#error_page

(1) if auth_request fail, it can not output custom error info to client by fail condition. For example, if token expired then output “token_exipred” , if user is banned then output “user_banned”. Now auth_request only return 401 httpcode without custom info, and can not pass error info to 401 httpcode location.

Not true. auth_request_set can be used to return metadata from an auth_request/js_content location that can then be used as part of an error_page location.

Does that help?