nginx 在不使用 lua 模块的情况下匹配请求体

标签 nginx nginx-reverse-proxy nginx-config

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;
        ...
    }
}

真正令我惊讶的是以下示例没有设置两个 header 中的任何一个:

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 中最后一个示例发生的情况的解释作者:张一春,着名《lua-nginx-module》作者和 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.

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

关于nginx 在不使用 lua 模块的情况下匹配请求体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64483262/

相关文章:

ruby-on-rails - Nginx:无法将 HTTP 响应转发回 HTTP 客户端

ruby-on-rails - Capistrano + NGINX Passenger 重启 Rails App

ssl - Nginx错误日志中的 "SSL_CTX_use_PrivateKey_file" "problems getting password error"表示什么?

ssl - CA 签名的 SSL 证书不受信任,声称是自签名的

ssl - 您能否终止 SSL 以提供自定义错误页面,但在传递到目标服务器之前重新加密?

Nginx 有条件地重写 uri

node.js - 带路径重写的 Nginx 代理配置

Nginx - 如何在 auth_request 返回 401 后重定向到登录页面

ssl - 如何禁用 ssl 证书并仅用于在 Nginx 中转发 443 端口上的流量?

nginx - 从 Ubuntu 20.04 中 Nginx 1.18 版的响应 header 中删除 'server' header