如同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
我遇到了同樣的問題,並找到了另一個我認為更好的解決方案。這個其他解決方案適用於 1.6+ 版本的 haproxy。它用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