okHttp 3.x 验证器未被调用
okHttp 3.x authenticator is not getting called
我需要通过需要身份验证的代理发出请求。
public class WebClient {
private final OkHttpClient httpClient;
private static WebClient webClient;
private WebClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (Configurator.getInstance().useProxy()) {
builder.proxySelector(new CustomProxySelector());
builder.authenticator((Route route, Response response) -> {
String credential = Credentials.basic("MYUSER", "MYPSW");
return response.request().newBuilder().header("Authorization", credential).build();
});
} else
builder.proxy(Proxy.NO_PROXY);
httpClient = builder
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.build();
}
}
但是使用调试器我发现永远不会调用身份验证器方法并且我收到 407 作为对任何请求的响应。
但是,当我将 HttpURLConnection 与 Authenticator.setDefault 一起使用时,它工作正常并且我可以使用我的代理身份验证:
public boolean hasInternetConnection() throws IOException {
Request httpRequest = new Request.Builder().url("http://www.google.com/").build();
// This fails with 407
Response httpResponse = httpClient.newCall(httpRequest).execute();
java.net.Authenticator authenticator = new java.net.Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return (new PasswordAuthentication("MYUSER", "MYPSW".toCharArray()));
}
};
java.net.Authenticator.setDefault(authenticator);
URL obj = new URL("http://www.google.com/");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
// This works with 200
int responseCode = con.getResponseCode();
return false;
}
所以我认为问题是:为什么 OkHttpClient.Builder.authenticator 方法没有被调用?
正如 Gimby 所指出的,其中一个问题是我调用了错误的方法。让我感到困惑的是,有时 proxyAuthenticator 没有被调用,我试图找出原因。
我开发的应用程序需要访问工作网络内外的资源。因此,当我需要外部访问时,我必须使用具有身份验证的代理。它是这样工作的:
- 已向 Internet 主机发出请求;
- ProxySelector 决定 HTTP 客户端为此使用代理
请求,因为它是互联网主机;
- 由于设置了代理,ProxyAuthenticator 被调用以发送
请求中的授权header.
然而,当向内部主机发出请求时,ProxySelector 决定不需要使用代理。 因此,不会调用 ProxyAuthenticator,因为没有活动代理。
以下是我对任何感兴趣的人的实现:
WebClient.java
public class WebClient {
private final OkHttpClient httpClient;
private static WebClient webClient;
private WebClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (Configurator.getInstance().useProxy()) {
CodeUtils.setProxy();
builder.proxySelector(new CustomProxySelector());
builder.proxyAuthenticator(new CustomProxyAuthenticator());
} else {
builder.proxy(Proxy.NO_PROXY);
CodeUtils.removeProxy();
}
httpClient = builder
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
}
public static WebClient getInstance() {
return webClient != null ? webClient : (webClient = new WebClient());
}
public static void reload() {
webClient = null;
}
public String doGet(String url) throws IOException {
Request httpRequest = new Request.Builder().url(url).build();
Response httpResponse = httpClient.newCall(httpRequest).execute();
if (httpResponse.code() != 200) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("success", false);
jsonObject.put("msg", httpResponse.body().string());
jsonObject.put("httpCode", httpResponse.code());
return jsonObject.toString();
}
return httpResponse.body().string();
}
public String doPost(String url, JSONObject body) throws IOException {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), body.toString());
Request request = new Request.Builder()
.header("Accept", "application/json")
.header("Content-type", "application/json; charset=UTF-8")
.url(url)
.post(requestBody).build();
Response response = httpClient.newCall(request).execute();
return response.body().string();
}
}
CustomProxyAuthenticator.java
public class CustomProxyAuthenticator implements Authenticator {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String username = Configurator.getInstance().getProxyUser();
String password = Configurator.getInstance().getProxyPassword();
String credential = Credentials.basic(username, password);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
}
CustomProxySelector.java
public class CustomProxySelector extends ProxySelector {
private Configurator configurator = Configurator.getInstance();
private List<String> nonProxyHosts = Arrays.asList(configurator.getNonProxyHosts().split("\|"));
private String proxyHost = configurator.getProxyHost();
private int proxyPort = configurator.getProxyPort();
@Override
public List<Proxy> select(URI uri) {
final List<Proxy> proxyList = new ArrayList<>(1);
String host = uri.getHost();
if (host.startsWith("127.0.0.1") || nonProxyHosts.contains(host))
proxyList.add(Proxy.NO_PROXY);
else
proxyList.add(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)));
return proxyList;
}
@Override
public void connectFailed(URI arg0, SocketAddress arg1, IOException arg2) {
}
}
我需要通过需要身份验证的代理发出请求。
public class WebClient {
private final OkHttpClient httpClient;
private static WebClient webClient;
private WebClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (Configurator.getInstance().useProxy()) {
builder.proxySelector(new CustomProxySelector());
builder.authenticator((Route route, Response response) -> {
String credential = Credentials.basic("MYUSER", "MYPSW");
return response.request().newBuilder().header("Authorization", credential).build();
});
} else
builder.proxy(Proxy.NO_PROXY);
httpClient = builder
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.build();
}
}
但是使用调试器我发现永远不会调用身份验证器方法并且我收到 407 作为对任何请求的响应。
但是,当我将 HttpURLConnection 与 Authenticator.setDefault 一起使用时,它工作正常并且我可以使用我的代理身份验证:
public boolean hasInternetConnection() throws IOException {
Request httpRequest = new Request.Builder().url("http://www.google.com/").build();
// This fails with 407
Response httpResponse = httpClient.newCall(httpRequest).execute();
java.net.Authenticator authenticator = new java.net.Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return (new PasswordAuthentication("MYUSER", "MYPSW".toCharArray()));
}
};
java.net.Authenticator.setDefault(authenticator);
URL obj = new URL("http://www.google.com/");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
// This works with 200
int responseCode = con.getResponseCode();
return false;
}
所以我认为问题是:为什么 OkHttpClient.Builder.authenticator 方法没有被调用?
正如 Gimby 所指出的,其中一个问题是我调用了错误的方法。让我感到困惑的是,有时 proxyAuthenticator 没有被调用,我试图找出原因。
我开发的应用程序需要访问工作网络内外的资源。因此,当我需要外部访问时,我必须使用具有身份验证的代理。它是这样工作的:
- 已向 Internet 主机发出请求;
- ProxySelector 决定 HTTP 客户端为此使用代理 请求,因为它是互联网主机;
- 由于设置了代理,ProxyAuthenticator 被调用以发送 请求中的授权header.
然而,当向内部主机发出请求时,ProxySelector 决定不需要使用代理。 因此,不会调用 ProxyAuthenticator,因为没有活动代理。
以下是我对任何感兴趣的人的实现:
WebClient.java
public class WebClient {
private final OkHttpClient httpClient;
private static WebClient webClient;
private WebClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (Configurator.getInstance().useProxy()) {
CodeUtils.setProxy();
builder.proxySelector(new CustomProxySelector());
builder.proxyAuthenticator(new CustomProxyAuthenticator());
} else {
builder.proxy(Proxy.NO_PROXY);
CodeUtils.removeProxy();
}
httpClient = builder
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
}
public static WebClient getInstance() {
return webClient != null ? webClient : (webClient = new WebClient());
}
public static void reload() {
webClient = null;
}
public String doGet(String url) throws IOException {
Request httpRequest = new Request.Builder().url(url).build();
Response httpResponse = httpClient.newCall(httpRequest).execute();
if (httpResponse.code() != 200) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("success", false);
jsonObject.put("msg", httpResponse.body().string());
jsonObject.put("httpCode", httpResponse.code());
return jsonObject.toString();
}
return httpResponse.body().string();
}
public String doPost(String url, JSONObject body) throws IOException {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), body.toString());
Request request = new Request.Builder()
.header("Accept", "application/json")
.header("Content-type", "application/json; charset=UTF-8")
.url(url)
.post(requestBody).build();
Response response = httpClient.newCall(request).execute();
return response.body().string();
}
}
CustomProxyAuthenticator.java
public class CustomProxyAuthenticator implements Authenticator {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String username = Configurator.getInstance().getProxyUser();
String password = Configurator.getInstance().getProxyPassword();
String credential = Credentials.basic(username, password);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
}
CustomProxySelector.java
public class CustomProxySelector extends ProxySelector {
private Configurator configurator = Configurator.getInstance();
private List<String> nonProxyHosts = Arrays.asList(configurator.getNonProxyHosts().split("\|"));
private String proxyHost = configurator.getProxyHost();
private int proxyPort = configurator.getProxyPort();
@Override
public List<Proxy> select(URI uri) {
final List<Proxy> proxyList = new ArrayList<>(1);
String host = uri.getHost();
if (host.startsWith("127.0.0.1") || nonProxyHosts.contains(host))
proxyList.add(Proxy.NO_PROXY);
else
proxyList.add(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)));
return proxyList;
}
@Override
public void connectFailed(URI arg0, SocketAddress arg1, IOException arg2) {
}
}