我正在使用 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 身份验证质询响应。这是一个问题,原因有二:
如果我使用由
InputStream
,它被认为是一个“不可重复”的请求,所以当收到 407 挑战时,我得到以下异常:org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity.
我可以通过将来自
InputStream
的实体主体数据缓冲到字符串或字节数组中来解决这个问题,以便在收到 407 质询时请求可重复,但这是低效的并且没有解决问题 2。- 必须重复每个请求,首先触发 407 质询,然后使用必要的额外 HTTP header 重复进行代理身份验证,效率非常低。我的一些客户端操作涉及对 RESTful Web 服务的大量 HTTP 请求,因此这种额外的流量和延迟是不幸的。
我的期望是,一旦 Jersey 客户端第一次成功通过代理服务器的身份验证,使用同一 Client
实例发出的所有后续请求将自动包含必要的 Proxy-Authorization
header 以防止任何进一步的 407 挑战。根据 this link,这似乎是 HTTP 1.1 的标准方法:
A proxy server sends the client a Proxy-Authenticate header, containing a challenge, in a 407 (Proxy Authentication Required) response. The client then repeats the initial request, but adds a Proxy-Authorization header that contains credentials appropriate to the challenge. After successful proxy authentication, a client typically sends the same Proxy-Authorization header to the proxy with each subsequent request, rather than wait to be challenged again.
所以我的问题是我需要将哪些配置设置应用到 Jersey Client 或底层 Apache HttpClient 传输层才能启用此行为?我已经看到各种其他帖子建议手动添加 Proxy-Authorization
header ,但我宁愿尽可能避免这种解决方法。我也在理想地寻找一种解决方案,该解决方案适用于我正在使用的所有三种类型的代理身份验证(基本、摘要和 NTLM)。
如果无法阻止所有这些额外的 407 挑战,我还想推荐以“可重复”方式从本地文件发布或放置数据时的最佳方法,以防止 407 代理身份验证挑战后出现问题。
最佳答案
最后,我通过将我的项目升级到 Jersey Client v2.6 并将客户端配置为自动缓冲我的所有 POST/PUT 请求来解决问题 1,以便它们“可重复”以响应返回的任何 407 挑战来自代理服务器。
通过在 ClientConfig
上设置以下属性,可以在 Jersey Client v2.5+ 中启用请求缓冲对象,它将请求实体处理模式从“分块”(默认)更改为“缓冲”:
config.property(ClientProperties.REQUEST_ENTITY_PROCESSING,
RequestEntityProcessing.BUFFERED);
这现在对我来说适用于我必须支持的所有三种类型的代理身份验证:基本、摘要和 NTLM。我只在用户配置了代理服务器时才启用这种“缓冲”模式,因为我认为除非绝对必要,否则最好坚持使用默认的“分块”模式。我担心在内存中缓冲大型 PUT/POST 请求的开销,以及不分块数据可能会降低效率。
现在我的客户端应用程序可以正常工作,但我仍然很想知道问题 2 的任何可能解决方案,因为最好只根据 Client
触发一个初始 407 代理身份验证质询。实例。由于摘要和 NTLM 身份验证固有的额外复杂性,我怀疑此问题的任何潜在解决方案都只能用于基本身份验证。
关于java - 重用授权 header 以防止 Jersey Client 的多个 407 代理身份验证挑战,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19681965/