4

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

这就是我添加对基本和摘要代理身份验证的支持的方式:

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. 如果我使用 an 提供的实体主体发出POSTorPUT请求(已在上一个请求中成功通过代理服务器进行身份验证)InputStream,则它被视为“不可重复”请求,因此当收到 407 质询时,我得到以下异常:

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

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

  2. 必须复制每个请求,首先触发 407 质询,然后重复必要的附加 HTTP 标头以进行代理身份验证,这是非常低效的。我的一些客户端操作涉及对 RESTful Web 服务的大量 HTTP 请求,因此这种额外的流量和延迟是不幸的。

Client我的期望是,一旦 Jersey 客户端第一次成功通过代理服务器进行身份验证,使用同一实例发出的所有后续请求将自动包含必要的Proxy-Authorization标头,以防止任何进一步的 407 挑战。根据此链接,这似乎是 HTTP 1.1 的标准方法:

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

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

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

4

1 回答 1

4

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

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

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

现在,这适用于我必须支持的所有三种类型的代理身份验证:Basic、Digest 和 NTLM。我只在用户配置了代理服务器时才启用这种“缓冲”模式,因为我认为除非绝对必要,否则最好坚持使用默认的“分块”模式。我担心在内存中缓冲大型 PUT/POST 请求的开销,以及不分块数据的潜在效率损失。

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

于 2014-03-15T20:52:49.560 回答