重用授权标头以防止Jersey客户端出现多个407代理身份验证问题

时间:2013-10-30 12:14:27

标签: java http apache-httpclient-4.x jersey-client proxy-authentication

我使用Jersey Client 2.0库(使用Apache HttpClient v4.2.5传输连接器)来使用RESTful Web服务。我的应用程序必须支持通过代理服务器与任何Basic,Digest或NTLM身份验证的连接。我已经添加了对所有这些类型的代理身份验证的支持,基本上一切都正常工作。

这就是我添加对Basic和Digest代理身份验证的支持:

ClientConfig config = new ClientConfig();
config.property(ApacheClientProperties.PROXY_URI, "http://www.proxy.com:5678");
config.property(ApacheClientProperties.PROXY_USERNAME, "proxy_user");
config.property(ApacheClientProperties.PROXY_PASSWORD, "proxy_password");
ApacheConnector connector = new ApacheConnector(config);
config.connector(connector);
Client client = ClientBuilder.newClient(config);

此外,我连接的RESTful Web服务本身也需要基本身份验证,我使用以下方法处理:

client.register( new HttpBasicAuthFilter("user", "password") );

但是,我的应用程序的行为并不完全符合我的要求:似乎我所做的每个HTTP请求都会导致代理服务器发出407认证质询响应。这是一个问题,原因有两个:

  1. 如果我使用POST提供的实体主体发出PUTInputStream请求(已在前一个请求中使用代理服务器成功通过身份验证),则被视为“不可重复”的请求,因此当收到407质疑时,我会得到以下例外:

    org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity.
    

    我可以通过将实体主体数据从InputStream缓冲到字符串或字节数组来解决此问题,以便在收到407质询时请求是可重复的,但这样做效率低且不地址问题2。

  2. 必须复制每个请求,首先触发407质询,然后重复使用必要的额外HTTP标头进行代理身份验证,效率非常低。我的一些客户端操作涉及到RESTful Web服务的大量HTTP请求,因此这种额外的流量和延迟是不幸的。
  3. 我的期望是,一旦Jersey客户端第一次成功通过代理服务器进行身份验证,使用相同Client实例发出的所有后续请求将自动包含必要的Proxy-Authorization标头以防止任何进一步的407挑战。根据{{​​3}},这似乎是HTTP 1.1的标准方法:

      

    代理服务器在407(需要代理身份验证)响应中向客户端发送包含质询的Proxy-Authenticate标头。然后,客户端重复初始请求,但添加了一个代理授权标头,其中包含适用于质询的凭据。成功进行代理身份验证后,客户端通常会在每次后续请求时向代理发送相同的Proxy-Authorization标头,而不是等待再次受到质询。

    所以我的问题是我需要将哪些配置设置应用于Jersey客户端或底层Apache HttpClient传输层才能启用此行为?我已经看到其他各种帖子建议手动添加Proxy-Authorization标题,但如果可能的话,我宁愿避免这种解决方法。我也非常理想地寻找能够与我正在使用的所有三种代理身份验证(Basic,Digest和NTLM)一起使用的解决方案。

    如果无法阻止所有这些额外的407挑战,我还希望在以“可重复”方式从本地文件发布或PUTing数据时采用最佳方法的建议,以防止407代理身份验证挑战后出现问题。< / p>

1 个答案:

答案 0 :(得分:3)

最后,我通过将项目升级到Jersey Client v2.6并将客户端配置为自动缓冲所有POST / PUT请求来解决问题1,以便它们“可重复”以响应任何407的挑战来自代理服务器。

通过在ClientConfig对象上设置以下属性,可以在Jersey Client v2.5 +中启用请求缓冲,这会将请求实体处理模式从“chunked”(默认)更改为“buffered”:< / p>

config.property(ClientProperties.REQUEST_ENTITY_PROCESSING,
                RequestEntityProcessing.BUFFERED);

现在我正在使用我必须支持的所有三种代理身份验证:Basic,Digest和NTLM。我只在用户配置代理服务器时才启用此“缓冲”模式,因为我认为除非绝对必要,否则最好坚持使用默认的“分块”模式。我担心在内存中缓冲大量PUT / POST请求的开销,以及在不对数据进行分块时可能会降低效率。

所以现在我的客户端应用程序正常运行,但我仍然非常有兴趣听到问题2的任何可能解决方案,因为最好只触发每个Client实例的单个初始407代理身份验证质询。我怀疑这个问题的任何潜在解决方案都只适用于基本身份验证,因为Digest和NTLM身份验证固有的额外复杂性。