Zuul 通过外部代理服务器路由请求

Zuul routing the requests through an external proxy server

我们当前的项目要求是将一些请求路由到第三方外部 api 服务器。为此,我们使用 spring 基于 zuul 的路由器服务。

zuul:
  routes
    test:
      path: /test/**
      serviceId: test
      url: http://my.api.server.com
    test2:
      path: /test2/**
      serviceId: test2
      url: http://my.api.server.com // but through an external proxy

现在的要求是,对于某些端点,对​​外部 api 服务器的请求已通过某些不属于我们的外部代理服务器进行路由,

如何通过 curl 执行此操作:

curl <external_api_server>/api/v1/user -k \
  -x tntqyhnhjym.sandbox.verygoodproxy.com:8080 \
  -H "Content-type: application/json" \
  -d '{"card_number": "tok_sandbox_t8VSoovCuHA779eJGZhKvg", ... }'

-x <proxy> 通过给定的代理重定向请求。 如何通过 spring-zuul 服务器做到这一点?

有一个线索,我得到了吗? https://github.com/spring-cloud/spring-cloud-netflix/issues/2320。不干净,因为我需要扩展 zuul

SimpleHostRoutingFilter

选项 1 - 反向代理服务器(使用代理)

您可以设置反向代理 - 配置为通过代理。您的反向代理将使用参数(例如 java 或 nodejs)启动以使用外部代理。这个反向代理将是一个不同的过程,它将通过您想要的代理传递所有请求。

您可以通过设置第二个 zuul 代理应用程序或通过 nodejs 反向代理 (express or node-http-proxy) 来实现。

第二个zuul应用(只针对外部)

因此,如果您使用 zuul,您将使用以下内容创建第二个应用程序:

   test2:
      path: /proxied-test2/**
      serviceId: test2
      url: http://my.api.server.com 

然后您将使用您的代理参数和特定端口(例如 9200)在同一台服务器上启动此服务器,例如

-Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888

原始申请

在您原来的应用程序中,您会将路线替换为以下内容。

zuul:
  routes
    test:
      path: /test/**
      serviceId: test
      url: http://my.api.server.com
    test2:
      path: /test2/**
      serviceId: test2
      url: http://localhost:9200/proxied-test2/

选项 2:使用可编写脚本的 http 代理服务器

您可以设置一个代理服务器,然后设置一些例外和规则,以决定哪些请求应该通过代理路由,哪些请求应该在没有代理的情况下工作。

第二步是将您的应用程序配置为使用在第 1 步中指定的本地代理服务器。为此,您可以使用以下 command-line 参数:

-Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888

我过去曾为代理服务器配置过排除列表,但我从未configured/scripted包含列表。在你的情况下,包含列表会更有意义,所以我会测试 scriptable/programmable 代理服务器,例如:


我也花了几个小时寻找这个问题的解决方案。我找到了一种比前面描述的方法更灵活、更容易的方法。

您可以实现自定义 ProxySelector 并为您想要的每个路由定义不同的代理。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.*;
import java.net.Proxy.Type;
import java.util.ArrayList;
import java.util.List;

public class CustomProxySelector extends ProxySelector {
    ProxySelector defaultProxySelector = ProxySelector.getDefault();

    ArrayList<Proxy> noProxy = new ArrayList<>();
    ArrayList<Proxy> proxies = new ArrayList<>();

    public CustomProxySelector(String proxyHost, int proxyPort) {
        noProxy.add(Proxy.NO_PROXY);
        proxies.add(new Proxy(Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)));
    }

    //define your custom proxy selection here
    @Override
    public List<Proxy> select(URI uri) {
        if (uri.getHost().matches("external.address.com")) {
            return proxies;
        }
        if (defaultProxySelector != null) {
            return defaultProxySelector.select(uri);
        }
        return noProxy;
    }

    @Override
    public void connectFailed(URI arg0, SocketAddress arg1, IOException arg2) {
        //error handling
    }
}

然后添加一个 CloseableHttpClient 类型的 bean,它会覆盖 Zuul 的标准 HttpClient,并使用您自定义的 ProxySelector 实现对其进行配置。

@Bean
@Primary
public CloseableHttpClient customHttpClientForZuulWithHttpProxyConfig(@Value("${your.proxy.host}") String proxyHost, @Value("${your.proxy.port}") int proxyPort) {
    SystemDefaultRoutePlanner routePlanner = new SystemDefaultRoutePlanner(new CustomProxySelector(proxyHost, proxyPort));
    return HttpClientBuilder.create().setRoutePlanner(routePlanner).build();
}

另请注意,spring 云不再支持 zuul。所以推荐的方法是切换到 spring 网关。