如何在nginx中创建自定义路径?

我有一个运行在nginx后面的应用。为了允许客户在相同的主机名下添加自己的工具,我们使用类似于这样的location

location /some-extension {
  rewrite ^/(.*) /$1 break;
  proxy_pass http://customers-app/$1/$args;
}

现在,我想把它变成动态的,使给定的客户可以创建零个或多个这样的位置。由于该应用程序是使用Docker部署的,因此无法通过手动编辑nginx配置来完成。

Nginx编译时带有perl和lua支持,因此我在考虑类似于以下内容的东西:

  • 使用形式为path1 url1 path-2 url2 ... pathn urln的环境变量配置外部工具。
  • 在一个特殊的“location”配置中,将请求URL的第一个路径段与环境变量进行匹配,并在找到时proxy_pass到相应的URL。

到目前为止,这就是我所拥有的:

location / {
    content_by_lua '
      local target_path = ngx.var.uri;
      local name = nil

      if target_path:len() > 0 then
        startAt = target_path:find("/") + 1
        endAt = target_path:find("/", startAt) - 1
        name = target_path:sub(startAt,endAt)
        ngx.say(name)
      end

      if name then
        local custom_proxies = os.getenv("CUSTOM_PROXIES");
        inString = custom_proxies:find("another ")
        if not inString then
          ngx.say("not in string")
        else
          startAt = custom_proxies:find(" ", inString + 1) + 1
          endAt = custom_proxies:find(" ", startAt)

          url = custom_proxies:sub(startAt,endAt)
          ngx.say(url)

        end
      end

    ';
  }

我知道我不应该使用content_by_lua,但它似乎有点工作。问题是我如何让它proxy_pass到指定的URL?

点赞
用户85010
用户85010

我是这样解决它的:

  • 环境变量应该是一个以空格分隔的名称和URL列表; key http://example.com/app1 key2 http://acme.com.

  • 一个 Lua 脚本将环境变量读入一个 table 中,以 key 为键和以下 URL 作为值。

  • 一个 nginx location 块将处理请求并使用 Lua 脚本查找要代理到的模块。

  • 一个函数将接受请求路径并从中找到键,然后在表中查找 URL。

下面是脚本:

local custom_proxies = os.getenv("CUSTOM_PROXIES")
local custom_modules = {}

local cutFrom = 0
local cutTo = 0

while cutTo < custom_proxies:len() do
  cutFrom = cutTo
  cutTo = custom_proxies:find(" ", cutFrom + 1)
  local name = custom_proxies:sub(cutFrom, cutTo - 1)
  cutFrom = cutTo + 1
  cutTo = custom_proxies:find(" ", cutFrom)

  if not cutTo then
    cutTo = custom_proxies:len() + 1
  end

  local url = custom_proxies:sub(cutFrom, cutTo - 1)
  custom_modules[name] = url
  cutTo = cutTo + 1
end

function custom_modules.get_url(target_path)
  local name = nil

  local startAt = target_path:find("/", 6) + 1
  local endAt = target_path:find("/", startAt)
  if not endAt then
    endAt = target_path:len()
  else
    endAt = endAt - 1
  end
  name = target_path:sub(startAt,endAt)
  if name then
    return custom_modules[name]
  else
    ngx.log(ngx.STDERR, "无法从 URI 推断出模块名称")
    return ""
  end
end

return custom_modules

下面是 nginx location

location /custom/ {
  set_by_lua $redirect_to '
    local custom_modules = require "read_proxies"
    local url = custom_modules.get_url(ngx.var.uri)

    if not url then
      ngx.log(ngx.STDERR, "未知自定义模块。")
    end
    return url
  ';

  if ($redirect_to = '') {
    return 404 '未知自定义模块。';
  }

  rewrite ^/custom/\w+/(.*) /$1 break;
  proxy_pass $redirect_to$1?$args;

}

这个思路是这样的,比如 /custom/foobar/path/to/something?page=2 的请求将使用 foobar 作为键来查找 URL,并将其与其余的路径和参数一起 proxy_pass 到它。

2016-05-01 17:27:10