简体   繁体   English

Apache 2.4 从负载平衡反向代理重定向不起作用但在非负载平衡反向代理中工作

[英]Apache 2.4 redirection from load-balanced reverse-proxy not working but working in non-load-balanced reverse-proxy

I have 2 NextJS internal servers/applications that is reverse-proxied by Apache 2.4.我有 2 个由 Apache 2.4 反向代理的 NextJS 内部服务器/应用程序。 Let's have the 2 internal servers as http://internal:3000/foo and http://internal:3001/foo and the external URL as http://external/foo . Let's have the 2 internal servers as http://internal:3000/foo and http://internal:3001/foo and the external URL as http://external/foo .

When the NextJS is accessed on the base path (ie http://internal:3000/foo ), it will be redirected to http://internal:3000/foo/bar/baz on HTTP Code 308 .在基路径(即http://internal:3000/foo )上访问 NextJS 时,会重定向到http://internal:3000/foo/bar/baz on HTTP Code 308 So over the reverse-proxy, I expected the same, that the redirection will happen from http://external/foo to http://external/foo/bar/baz .因此,通过反向代理,我预计会发生同样的情况,重定向将从http://external/foohttp://external/foo/bar/baz发生。
The config in next.config.js is as follow next.config.js中的配置如下

... module.exports = {... async redirects() { return [ { source: '/', destination: '/bar/baz', permanent: true } ] }, basePath: 'foo' }

What happen is that this redirection works perfectly when I tried reverse-proxy to only 1 NextJS application without load balancing , eg I only reverse proxy to http://internal:3000/foo .发生的情况是,当我尝试反向代理到只有 1 个 NextJS 应用程序而没有负载平衡时,这种重定向工作得很好,例如,我只反向代理到http://internal:3000/foo
The config that I used is as follow我使用的配置如下

<Location "/foo"> ProxyPass "http://localhost:3000/foo" ProxyPassReverse "http://localhost:3000/foo" </Location>

But the redirection does not work when I tried reverse-proxy to 2 NextJS application on load balancing .但是,当我尝试反向代理到 2 NextJS application on load balance 时,重定向不起作用
The config that I used is as follow我使用的配置如下

<Proxy "balancer://example"> BalancerMember "http://localhost:3000/foo" BalancerMember "http://localhost:3001/foo" </Proxy> <Location "/foo"> ProxyPass "balancer://example" ProxyPassReverse "balancer://example" </Location>

What happen instead is that it will keep redirecting from http://external/foo to http://external/foo ie infinite redirect that result in TOO_MANY_REDIRECT .相反,它将继续从http://external/foo重定向到http://external/foo即无限重定向,从而导致TOO_MANY_REDIRECT

It baffles me that the redirection works in non load-balancing scenario but failed when using load-balancing.令我感到困惑的是,重定向在非负载平衡情况下有效,但在使用负载平衡时失败。 Any ideas what is actually happening?任何想法实际上发生了什么? Is there response header being written that I am unaware of when using proxy load-balancing?是否有响应 header 被写入我在使用代理负载平衡时不知道? Thanks谢谢

Update/progress (1):更新/进展(1):

I suspect there is rewriting happening in mod_proxy_balancer.c in following section我怀疑在以下部分的mod_proxy_balancer.c中发生了重写

 access_status = rewrite_url(r, *worker, url); /* Add the session route to request notes if present */ if (route) { apr_table_setn(r->notes, "session-sticky", sticky); apr_table_setn(r->notes, "session-route", route); /* Add session info to env. */ apr_table_setn(r->subprocess_env, "BALANCER_SESSION_STICKY", sticky); apr_table_setn(r->subprocess_env, "BALANCER_SESSION_ROUTE", route); } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01172) "%s: worker (%s) rewritten to %s", (*balancer)->s->name, (*worker)->s->name, *url); return access_status;

which can be found in https://github.com/apache/httpd/blob/317108ee6e84ae47bd0f6121e3a64074c5d68c7b/modules/proxy/mod_proxy_balancer.c#L631-L647可以在https://github.com/apache/httpd/blob/317108ee6e84ae47bd0f6121e3a64074c5d68c7b/modules/proxy/mod_proxy_balancer.c#L631-L647中找到

Update/progress (2):更新/进展(2):

I turned on mod_dumpio to log all the incoming and outgoing traffic into and from apache, and have confirmed that there is indeed a rewriting happening.我打开mod_dumpio来记录所有进出 apache 的传入和传出流量,并确认确实发生了重写。

The rewriting is happening as follow:重写发生如下:

  1. GET /foo , which is the original request sent to the external server. GET /foo ,这是发送到外部服务器的原始请求。
  2. GET /foo/ , which is the request sent to the internal server. GET /foo/ ,这是发送到内部服务器的请求。 Notice there is rewriting of adding slash at the end.请注意在末尾添加斜线的重写。
  3. Location /foo , which is the internal server's redirection response location. Location /foo ,这是内部服务器的重定向响应位置。 This is an intended location because in internal server, GET /foo/ will be redirected to Location /foo while GET /foo will be redirected to Location /foo/bar/baz .这是一个预期的位置,因为在内部服务器中, GET /foo/将被重定向到Location /fooGET /foo将被重定向到Location /foo/bar/baz Under normal circumstances the redirection will be handled by the internal server, meaning that GET /foo/ will result in redirection resulting in GET /foo , eventually yielding Location /foo/bar/baz but this does not happen in reverse-proxy.在正常情况下,重定向将由内部服务器处理,这意味着GET /foo/将导致重定向导致GET /foo ,最终产生Location /foo/bar/baz但这不会发生在反向代理中。
  4. Location /foo , which is the external server's redirection response location. Location /foo ,即外部服务器的重定向响应位置。 Because (4) and (1) is the same URL, therefore it will create a redirection loop.因为(4)和(1)是同一个URL,所以会产生重定向循环。

With the rewriting confirmed, now I am looking whether there is way to solve this behavior.确认重写后,现在我正在寻找是否有办法解决这种行为。

I finally managed to fix the issue, and pertaining to the 2nd update above, I managed to find where the "rewriting" happen which helped me fix the issue.我终于设法解决了这个问题,并且关于上面的第二次更新,我设法找到了“重写”发生的位置,这帮助我解决了这个问题。


tl;dr
The fix is basically moving the path from BalancerMember to the balancer itself, ie修复基本上是将路径从BalancerMember移动到平衡器本身,即

<Proxy "balancer://example/foo"> // used to be "balancer://example" BalancerMember "http://localhost:3000" // used to be "http://localhost:3000/foo" BalancerMember "http://localhost:3001" // used to be "http://localhost:3001/foo" </Proxy> // change to point to the balancer accordingly <Location "/foo"> ProxyPass "balancer://example/foo" ProxyPassReverse "balancer://example/foo" </Location>

As for my finding, the "rewriting" is not so much of rewriting but is actually URL canonicalisation performed by Apache, in mod_proxy_balancer or mod_proxy_http modules (or depends on your scheme).至于我的发现,“重写”并不是重写,而是实际上是 Apache 在mod_proxy_balancermod_proxy_http模块中执行的 URL 规范化(或取决于您的方案)。 example of canonicalisation source code in mod_proxy_balancer mod_proxy_balancer 中的规范化源代码示例

Changing balancer://example -> balancer://example/foo makes its URL scheme structure wise same to http://localhost:3000/foo , which when undergoing canonicalisation will not yield trailing slash at the end, which is caused by balancer://example not having path right after the "host", and therefore with the said change the behaviour for reverse-proxy using either load balancer or not will finally be the same.更改balancer://example -> balancer://example/foo使其 URL 方案结构与http://localhost:3000/foo相同,在进行规范化时不会在末尾产生斜杠,这是由balancer://example在“主机”之后没有路径,因此通过上述更改,使用负载均衡器或不使用负载均衡器的反向代理的行为最终将相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM