NGINX - OpenResty - Как отменить прокси-вызов для 2 разных серверов на основе строки?
Я пытаюсь настроить NGINX/OpenResty для прокси-вызовов SOAP на 2 разных сервера на основе строки, присутствующей в запросе SOAP.
Что я могу сделать: я могу прокси-запросы на 2 разных сервера в зависимости от пути, который вызывает клиент SOAP:
location /pathA {
proxy_pass http://www.ServerA.com/PathA/;
}
location /pathB {
proxy_pass http://www.ServerB.com/PathB/;
}
Что я не могу сделать:
Я не могу разделить трафик в зависимости от содержания запроса. Основная причина, по которой я верю, заключается в том, что я не могу правильно собрать скрипт LUA для извлечения информации и последующего использования для прокси-запроса.
location / {
conten_by_lua '
ngx.req.read_body()
local match = ngx.re.match(ngx.var.request_body,"STRING TO FIND")
if match then
proxy_pass http://www.ServerA.com/PathA/;
else
proxy_pass http://www.ServerB.com/PathB/;
как я могу этого достичь?
Я установил OpenResty и LUA работает нормально.
Я думаю, что я где-то читал, что если запрос не HTTP POST ngx.req.read_body()
не будет работать. Это верно?
Спасибо за помощь.
2 ответа
Вы почти сделали это сами, единственное, что я сделал бы по-другому, это использовать rewrite_by_lua
вместо content_by_lua
:
location / {
set $proxy "";
rewrite_by_lua '
ngx.req.read_body()
local match = ngx.re.match(ngx.var.request_body, "STRING TO FIND")
if match then
ngx.var.proxy = "www.ServerA.com"
else
ngx.var.proxy = "www.ServerB.com"
end
';
proxy_pass http://$proxy$uri;
}
Если запрос не является HTTP POST или имеет пустое тело, ngx.req.read_body()
вернусь nil
, так что лучше добавить дополнительную проверку:
location / {
set $proxy "";
rewrite_by_lua '
ngx.req.read_body()
local body = ngx.var.request_body
if (body) then
local match = ngx.re.match(body, "STRING TO FIND")
if match then
ngx.var.proxy = "www.ServerA.com"
else
ngx.var.proxy = "www.ServerB.com"
end
else
ngx.status = ngx.HTTP_NOT_FOUND
ngx.exit(ngx.status)
end
';
proxy_pass http://$proxy$uri;
}
Вы также можете ограничить допустимые методы:
location / {
limit_except POST { deny all; }
...
}
Еще кое-что. В этой конфигурации, если вы укажете свои бэкэнды с доменными именами вместо IP-адресов, вам понадобится resolver
Директива в вашем конфиге. Вы можете использовать свой локальный сервер имен, если он у вас есть, или использовать что-то внешнее, например, общедоступный DNS Google (8.8.8.8) или DNS, предоставленный вам вашим провайдером.
Вот фрагменты кода, которые я использовал в openresty, чтобы различать веб-перехватчики dev и prod в соответствии с опубликованным телом json:
server {
listen 8080;
resolver 114.114.114.114 8.8.8.8 valid=30s;
location /webhook {
limit_except POST { deny all; }
set $proxy "";
rewrite_by_lua_block {
local devWebhook = "myservice.dev" -- todo
local prodWebhook = "mysevice.prod" -- todo
function getFile(file_name)
local f = assert(io.open(file_name, 'r'))
local string = f:read("*all")
f:close()
return string
end
ngx.req.read_body()
local data = ngx.req.get_body_data()
if nil == data then
local file_name = ngx.req.get_body_file()
if file_name then
data = getFile(file_name)
end
end
local json = require("cjson.safe")
local t = json.decode(data)
if not (type(t) == "table" and t["msg"]) then
ngx.exit(400)
end
local msg = ngx.unescape_uri(t["msg"])
if not (type(msg) == "string" and #msg > 0) then
ngx.exit(400)
end
if string.find(msg, '"title":".*test product.*"') then
ngx.var.proxy = devWebhook
else
ngx.var.proxy = prodWebhook
end
}
proxy_pass http://$proxy$uri;
}
}