基于路径的Haproxy重定向

基于路径的Haproxy重定向

如同HAProxy reqrep 删除后端请求中的 URI

我们关注的问题如下。

我们有一些应用程序在同一个域中使用不同的上下文根运行。但是并非所有 URL 客户端都发生了更改。

如果请求与旧路径匹配,我想在 haproxy 中使用 301 重定向进行重定向。

举个http://example.com/abc例子http://example.com/def

...
frontend https
  bind *:{{ proxy_port }} ssl crt /etc/haproxy/bundle_dh.pem ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4 no-sslv3
  http-request set-header X-Forwarded-Proto https if { ssl_fc }
  http-request set-header X-Forwarded-Port %[dst_port]

  acl has_legacy_abc path_beg /abc
  acl has_legacy_def path_beg /def
  redirect location 301 https://abcdomain.com/{PATH_WITHOUT_ABC} if { has_legacy_abc }
  redirect location 301 https://defdomain.com/{PATH_WITHOUT_ABC} if { has_legacy_def }

  use backend abc_backend if { hdr(Host) -i abcdomain.com }
  use backend def_backend if { hdr(Host) -i defdomain.com }
...

问题是如何在重定向中保留路径。我可以进行绝对重定向。

看了看,reqrep但这似乎是在传递到后端之前更改请求。我想告诉所有访问者他们应该转到新域名。

答案1

可以使用一些临时标题来完成此操作,这些标题插入您的acl定义和use_backend关键字之间:

http-request set-header X-Location-Path %[capture.req.uri] if has_legacy_abc OR has_legacy_def

http-request replace-header X-Location-Path [^/]+/(.*) \1 if has_legacy_abc OR has_legacy_def

http-request redirect location https://abcdomain.com/%[hdr(X-Location-Path)] if has_legacy_abc
http-request redirect location https://defdomain.com/%[hdr(X-Location-Path)] if has_legacy_def

根据域/路径和所需重定向的实际配置,甚至可以将其全部折叠成一组指令,如下所示:

...
frontend https
  bind *:{{ proxy_port }} ssl crt /etc/haproxy/bundle_dh.pem ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4 no-sslv3
  http-request set-header X-Forwarded-Proto https if { ssl_fc }
  http-request set-header X-Forwarded-Port %[dst_port]

  acl has_legacy path_beg /abc /def

  http-request set-header X-Location-Path %[capture.req.uri] if has_legacy
  http-request set-header X-Location-Host %[capture.req.uri] if has_legacy

  http-request replace-header X-Location-Host /([^/]*)/ \1 if has_legacy
  http-request replace-header X-Location-Path [^/]+/(.*) \1 if has_legacy

  http-request redirect location https://%[hdr(X-Location-Host)]domain.com/%[hdr(X-Location-Path)] if has_legacy_abc

  use backend abc_backend if { hdr(Host) -i abcdomain.com }
  use backend def_backend if { hdr(Host) -i defdomain.com }
...

如果路径和域的数量很大,则可以使用地图(其中键是路径,值是目标主机)以进一步简化事情。

答案2

我遇到了同样的问题,并找到了另一个我认为更好的解决方案。这个解决方案适用于 haproxy 1.6+ 版本。它使用http 请求和 regsub

如果我重写你的例子:

frontend https
  bind *:{{ proxy_port }} ssl crt /etc/haproxy/bundle_dh.pem ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4 no-sslv3
  acl has_legacy_abc path_beg /abc
  acl has_legacy_def path_beg /def
  http-request redirect code 301 location https://%[hdr(host)]%[url,regsub(^/abc,/newabc,)] if has_legacy_abc

相关内容