配置Apache HttpClient通过代理/负载均衡器访问服务(覆盖主机头)

我在使用Apache HttpClient连接到虚拟化开发环境外部的服务时遇到问题。 要访问互联网(例如api.twitter.com),我需要调用本地URL(例如api.twitter.com.dev.mycompany.net),然后将请求转发给真正的主机。

问题是,对于我发送的任何请求,我得到404 Not Found响应。

我尝试使用wget对其进行调试,问题是,目标服务器通过使用请求URL和Host头中的主机名来识别所需的资源。 由于主机名不匹配,因此无法找到资源。

我(尝试通过)在客户端上设置http.virtual-host参数来尝试覆盖Host头,但是没有成功:

HttpClient client = new DefaultHttpClient(); if (envType.isWithProxy()) { client.getParams().setParameter(ClientPNames.VIRTUAL_HOST, "api.twitter.com"); } 

技术细节:

  1. 客户端在RESTeasy中用作执行程序来调用REST API。 因此,“手动”设置虚拟主机(如此处所述)不是一种选择。

  2. 一切都通过HTTPS / SSL完成 – 而不是我认为它有所作为。

编辑1:使用HttpHost而不是String也没有所需的效果:

 HttpClient client = new DefaultHttpClient(); if (envType.isWithProxy()) { HttpHost realHost = new HttpHost("api.twitter.com", port, scheme); client.getParams().setParameter(ClientPNames.VIRTUAL_HOST, realHost); } 

编辑2:进一步调查显示,需要在请求对象上设置参数。 以下是设置虚拟主机的HttpClient的代码v.4.2-aplha1:

 HttpRequest orig = request; RequestWrapper origWrapper = wrapRequest(orig); origWrapper.setParams(params); HttpRoute origRoute = determineRoute(target, origWrapper, context); virtualHost = (HttpHost) orig.getParams().getParameter( ClientPNames.VIRTUAL_HOST); 

params是从客户端传递的参数。 但是从请求参数中读取’virtualHost’的值。

因此,这会将问题的性质更改为:如何在请求中设置VIRTUAL_HOST属性?

ClientPNames.VIRTUAL_HOST是用于覆盖HTTP请求中的物理主机名的正确参数。 我建议在请求对象而不是客户端对象上设置此参数。 如果这不会产生预期的效果,请在此处或HttpClient用户列表中发布会话的完整连线/上下文日志(请参阅日志指南以获取说明)。


跟进

好。 我们来拿一把更大的大锤。 可以使用拦截器覆盖Host头的内容。

 DefaultHttpClient client = new DefaultHttpClient(); client.addRequestInterceptor(new HttpRequestInterceptor() { public void process( final HttpRequest request, final HttpContext context) throws HttpException, IOException { request.setHeader(HTTP.TARGET_HOST, "www.whatever.com"); } }); 

可以使拦截器足够聪明,有选择地覆盖头部,仅适用于特定主机。