不使用 lua 模块的 nginx 匹配请求正文

nginx match request body without using lua module

nginx 有没有办法根据请求正文是否有字符串来做一些事情? 我确信我可以使用 Lua 模块来做到这一点。 我正在尝试找出是否有单独使用nginx的方法。

我希望像下面这样的东西能奏效。

 location /students-api {
    if ($request_body ~* "(.*)specialstudent(.*)" ) {
      set  $student_status  'special';
    }
  // and use student_status for some logic
 } 

我认为应该可以工作,但是需要测试。在实践中,我只使用 $request_body 进行日志记录,不确定它是否在请求处理的重写阶段可用。这是一个 official description 表示:

The variable’s value is made available in locations processed by the proxy_pass, fastcgi_pass, uwsgi_pass, and scgi_pass directives when the request body was read to a memory buffer.

此外,如果您以后不使用它们,则不需要那些捕获组来检查变量是否存在子字符串(实际上,您只是在浪费资源以将它们保留在内存中),只是 if ($request_body ~* "specialstudent") { ... }应该够了。

更新

这是另一种有更多机会工作的方法,因为 proxy_add_header 指令肯定晚于请求处理的重写阶段执行:

map $request_body $special {
    ~*"specialstudent"    "special";
    # otherwise '$special' variable value will be empty
}
server {
    ...
    location /students-api {
        ...
        proxy_set_header X-Student-Status $special;
        ...
    }
}

更新 2

测试完所有这些后,我可以确认 if 方法不起作用:

server {
    ...
    location /students-api {
        if ($request_body ~* "specialstudent") {
            set $student_status "special";
        }
        proxy_set_header X-Student-Status $student_status;
        ...
    }
}

正如预期的那样,$request_body 变量不会在请求处理的重写阶段进行初始化。但是,map 方法按预期工作:

map $request_body $student_status {
    ~*"specialstudent"    "special";
    # otherwise '$special' variable value will be empty
}
server {
    ...
    location /students-api {
        proxy_set_header X-Student-Status $student_status;
        ...
    }
}

真正让我吃惊的是下面的例子没有设置任何两个 headers:

map $request_body $student_status {
    ~*"specialstudent"    "special";
    # otherwise '$special' variable value will be empty
}
server {
    ...
    location /students-api {
        if ($request_body ~* "specialstudent") {
            set $student_special "special";
        }
        proxy_set_header X-Student-Status $student_status;
        proxy_set_header X-Student-Special $student_special;
        ...
    }
}

在请求处理的早期重写阶段以某种方式访问​​ $request_body 变量会导致 map 翻译也停止工作。我暂时没有对这种行为的解释,如果有人能解释这里发生的事情,我将不胜感激。

更新 3

我想我终于找到了对 Nginx Tutorials written by Yichun Zhang, the author of famous lua-nginx-module and the OpenResty 包中最后一个示例所发生情况的解释:

Some Nginx variables choose to use their value containers as a data cache when the "get handler" is configured. In this setting, the "get handler" is run only once, i.e., at the first time the variable is read, which reduces overhead when the variable is read multiple times during its lifetime.

看起来 $request_body 变量的行为正是这样,如果在 NGX_HTTP_REWRITE_PHASE 早期被访问(请参阅请求处理阶段 description)。它的值,如果在该阶段被读取,将被缓存为一个空值,并在后面的请求处理阶段变得无用。