【问题标题】:nginx proxy_pass based on whether request method is POST, PUT or DELETEnginx proxy_pass 基于请求方法是 POST、PUT 还是 DELETE
【发布时间】:2012-01-25 08:52:48
【问题描述】:

我有两个 iKaaro 实例在端口 8080 和 9080 上运行,其中 9080 实例是只读的。

我不确定如何使用 nginx,例如,如果请求方法是 POST、PUT、DELETE 然后发送到写入实例 (8080) 否则发送到 9080 实例。

我使用正则表达式的位置做了一些事情,但这不正确。

http://wiki.nginx.org/HttpLuaModule我看到有可以调用的“HTTP方法常量”,所以添加一个位置块是否正确:

location ~* "(ngx.HTTP_POST|ngx.HTTP_DELETE|ngx.HTTP_PUT)" {
    proxy_pass http://127.0.0.1:8080;

谢谢

【问题讨论】:

  • 你能更好地解释一下这个问题吗?你试过那个设置吗?你有任何错误(哪些)?

标签: lua nginx


【解决方案1】:

我刚刚做了一个快速测试,这对我有用:

server {
  location / {
    # This proxy_pass is used for requests that don't
    # match the limit_except
    proxy_pass http://127.0.0.1:8080;

    limit_except PUT POST DELETE {
      # For requests that *aren't* a PUT, POST, or DELETE,
      # pass to :9080
      proxy_pass http://127.0.0.1:9080;
    }
  }
}

【讨论】:

  • 它也不依赖任何第三方模块
  • 这很令人困惑,首先你说don't match the limit_except,在limit_except之前你说aren't,所以如果我有一个GET请求,它与limit_except不匹配(所以@ 987654326@根据评论),而且GET不是“PUT,POST或DELETE”,所以9080
  • 我已将第二条评论移到 limit_except 块中。这是否让您更清楚哪些请求将由该内部块处理,而不是外部 proxy_pass?
【解决方案2】:

我假设您已经掌握了基础知识。即,您已经在服务器上安装了 Lua 5.1,或者更好的是 LuaJIT 2.0,使用 ngx_lua 模块编译了 Nginx,并根据需要配置了 ngx_lua。

有了它,这将完成这项工作:

location /test {
    content_by_lua '
        local reqType = ngx.var.request_method
        if reqType == ngx.HTTP_POST 
            OR reqType == ngx.HTTP_DELETE 
            OR reqType == ngx.HTTP_PUT 
        then
            res = ngx.location.capture("/write_instance")
        else
            res = ngx.location.capture("/read_instance")
        end
        ngx.say(res.body)
    ';
}
location /write_instance {
    internal;
    proxy_pass http://127.0.0.1:8080;
}
location /read_instance {
    internal;
    proxy_pass http://127.0.0.1:9080;
}

更新

我想也许你专门在更大范围内使用 Lua。下面的示例也将按照与 limit_except 相同的原理工作。

location /test {
    if ($request_method !~* GET) {
        # For Write Requests
        proxy_pass http://127.0.0.1:8080;
    }
    # For Read Requests
    proxy_pass http://127.0.0.1:9080;
}

“if”和“limit_except”块都有效地创建了一个嵌套的位置块,一旦条件匹配,只有这样创建的内部位置块的内容处理程序(“proxy_pass”)将被执行。

没有完全理解这就是为什么有时说 if 是“邪恶的”,但在这种情况下,“if”和“limit_except”共同的“邪恶”行为可能正是您想要的。

三个选项供你选择!

但是请注意,如果您需要设置任何其他指令,则必须注意不要被使用“if”或“limit_except”选项的“邪恶”行为所困扰。

IE,如果您在“if”或“limit_except”块内设置指令,它可能在其外部无效,类似地,外部设置的某些内容可能会在内部继承。因此,您必须注意两种方法的默认值是如何被继承的,或者不被继承。

If is Evil 页面上列出的所有潜在问题同样适用于此处的“if”和“limit_except”。正如该页面所建议的,基于 Lua 的脚本方法将避免许多潜在的陷阱。

祝你好运!

【讨论】:

  • 感谢详细的解释,所以我需要注意 IfiSEvil 是否需要运行其他指令。我可能需要,因为我还需要包含特定的 URL,例如 location ~* "(login|new_content)" { ... 但我会尝试弄清楚并带着我的 nginx.conf 文件回到这里,看看它是否可以改进。
  • 尝试按特定问题分隔查询。我假设通过您拥有的三个选项,关于如何在 Nginx 中基于请求方法路由请求的具体问题已得到详尽解答。您可以直接使用“if”,也可以使用“limit_except”(一种考虑潜在问题的 if 语句),或者使用脚本方法(例如给出的 Lua 示例)来避免这些问题。您可能需要考虑接受其中一个或另一个答案,如果还有其他问题,请提出一个新问题。
  • 这是一个内容丰富的回复。我正在尝试使用您的第一个解决方案(content_by_lua 方法),但我注意到对ngx.say(res.body) 的调用不包括响应对象的标头,仅包括正文。如何将响应的标头写入最终的 ngx 响应?
【解决方案3】:

我推荐 nginx 地图功能。这超出了您的位置块:

map $request_method $destination {
    default 8080;
    PUT 9080;
    POST 9080;
    DELETE 9080;
}

然后在您的位置块中:

proxy_pass http://127.0.0.1:$destination

这也是所有正则表达式,因此您可以执行以下操作:

map $request_method $cookie_auth $destination {
    default 8080;
    "^POST " 9080;
    "^PUT someAuthCookieValue" 9080;
}

另外,这完全避免了 if 的使用。这真是太棒了。我用它来将 WordPress 集群中的所有写入流量引导到远程节点上的一个 FastCGI TCP 套接字,但将读取流量发送到本地 FastCGI UNIX 套接字。

【讨论】:

  • 我想知道为什么这个得到这么少的选票实际上是最好的答案。
  • 但是第二个例子给出的错误,正则表达式的使用是由~字符串前缀定义的,正确的等价物是map "$request_method:$cookie_auth" $destination { default 8080; "~^POST:" 9080; "~^PUT:someAuthCookieValue$" 9080; }
【解决方案4】:

如果有人想通过请求方法简单地创建条件,语法是:

if ($request_method = DELETE ) {
   . . . 
}

【讨论】:

猜你喜欢
  • 2013-09-27
  • 2018-02-19
  • 2015-05-17
  • 1970-01-01
  • 1970-01-01
  • 2021-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多