我在让 Apache HttpClient 连接到虚拟化开发环境外部的服务时遇到问题。 要访问互联网(例如 api.twitter.com),我需要调用本地 URL(例如 api.twitter.com.dev.mycompany.net),然后将请求转发到真实主机。
问题是,无论我发送什么请求,我都会收到 404 Not Found 响应。
我已经尝试使用 wget 对其进行调试,问题似乎在于,目标服务器通过使用请求 URL 和主机 header 中的主机名来识别所需的资源。由于主机名不匹配,无法找到资源。
我曾(未成功)尝试通过在客户端上设置 http.virtual-host 参数来覆盖 Host header ,如下所示:
HttpClient client = new DefaultHttpClient();
if (envType.isWithProxy()) {
client.getParams().setParameter(ClientPNames.VIRTUAL_HOST, "api.twitter.com");
}
技术细节:
客户端在 RESTeasy 中用作执行器来调用 REST API。因此,“手动”设置虚拟主机(如 here 所述)不是一种选择。
一切都通过 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 用户列表中发布 session 的完整连线/上下文日志(有关说明,请参阅 logging guide)。
跟进
好的。让我们拿一个更大的大锤。可以使用拦截器覆盖 Host
header 的内容。
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");
}
});
可以使拦截器足够聪明,仅针对特定主机有选择地覆盖 header 。
关于java - 配置 Apache HttpClient 以通过代理/负载平衡器访问服务(覆盖主机 header ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9499697/