我有一个独立的Java客户端,试图通过NTLM代理执行RMI。 它是多线程的。 我正在使用Apache httpclient 4.5.6。 我在5分钟的超时周期内获得了代理。
这种基本情况有效,只要有两个线程在代理超时的同一时间未同时发出请求,代理就会向每5分钟重新进行一次身份验证。然后失败。一旦失败,所有后续尝试都会失败。
我附上了wireshark屏幕截图以进行澄清(屏幕截图来自4.5.2,但我升级到4.5.6并看到了相同的行为)。
一个好的周期看起来像
一个糟糕的周期看起来像
在我看来,这看起来像是非线程安全代码中的多线程竞争条件。
使用Apache httpclient 4.5.2,它只是传播了407,我在CloseableHttpResponse.getStatusLine()。getStatusCode()中检测到它。 通过Apache httpclient 4.5.6,我看到了
java.lang.IllegalStateException: Auth scheme is null
at org.apache.http.util.Asserts.notNull(Asserts.java:52)
at org.apache.http.impl.auth.HttpAuthenticator.ensureAuthScheme(HttpAuthenticator.java:229)
at org.apache.http.impl.auth.HttpAuthenticator.generateAuthResponse(HttpAuthenticator.java:184)
at org.apache.http.impl.execchain.MainClientExec.createTunnelToTarget(MainClientExec.java:484)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:411)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
有什么主意如何防范或解决它或从中恢复? (除了通话同步,这会大大降低原本已经很慢的应用的速度)
该应用的一些代码段:
// this is done only once
HttpClientBuilder builder = HttpClients.custom();
SocketConfig.Builder socketConfig = SocketConfig.custom();
RequestConfig.Builder requestConfig = RequestConfig.custom();
HttpHost proxy = new HttpHost(proxyHost, proxyPort);
builder.setProxy(proxy);
requestConfig.setProxy(proxy);
builder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
String localHost = getLocalHostname();
credentialsProvider.setCredentials(
new AuthScope(proxyHost, proxyPort, AuthScope.ANY_REALM, "ntlm"),
new NTCredentials(user, password, localHost, domain));
builder.setDefaultCredentialsProvider(credentialsProvider);
builder.setDefaultSocketConfig(socketConfig.build());
builder.setDefaultRequestConfig(requestConfig.build());
CloseableHttpClient client = builder.build();
...
// cached, we use the same one every time in accordance with section 4.7 of
// https://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/authentication.html
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credentialsProvider);
...
// new HttpPost every time
HttpPost postMethod = new HttpPost(uri);
postMethod.setEntity(new ByteArrayEntity(bytesOut.toByteArray()));
response = client.execute(postMethod, context);
答案 0 :(得分:1)
HttpContext
实例是完全线程安全的。但是,存储在上下文中的某些属性(如身份验证握手状态)显然不是。确保HttpContext
实例不会同时更新,并且该问题应消除。
答案 1 :(得分:0)
谢谢奥列格(Oleg),这是我的工作,到目前为止,它似乎已经可以正常工作了(太久不能发表评论,但我想分享我的代码)
renderList(){
const { player } = this.state
const { players } = this.props
// ignore user's typing case
const iPlayer = player.toLowerCase()
const filteredPlayers = players.filter(p =>
p.name.toLowerCase().includes(iPlayer)
)
// now, map to the filteredPlayers