【发布时间】:2022-12-24 04:31:30
【问题描述】:
我正在尝试从 HTTP 相机下载图像。问题是,有问题的相机需要(基本)身份验证。我知道不应该在 HTTP 上使用基本身份验证,但我们正在谈论一个隔离的网络,所以这不是这里的重点。
我正在尝试为此使用 Java17 本机 java.net.http.HttpClient。我正在使用以下代码:
protected BufferedImage retrieveImage(URI uri) throws IOException, InterruptedException {
log.trace("Using authorization header of '{}'", basicAuthString);
HttpRequest request = HttpRequest.newBuilder()
.uri(uri)
.header("Authorization", basicAuthString)
.GET()
.timeout(Duration.ofSeconds(20))
.build();
return retrieveImage(request);
}
private BufferedImage retrieveImage(HttpRequest request) throws IOException, InterruptedException {
HttpResponse<byte[]> response = null;
try {
response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
} catch (ConnectException ex) {
log.error("Connection refused when downloading image from " + uri.toString());
return null;
}
if (response.statusCode() != 200) { // ok
log.error("Error retrieving image, status code is {}", response.statusCode());
return null;
}
ByteArrayInputStream bis = new ByteArrayInputStream(response.body());
BufferedImage image = ImageIO.read(bis);
return image;
}
HttpClient 变量(上面代码中的客户端)由以下人员创建:
this.client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.followRedirects(HttpClient.Redirect.NORMAL)
.authenticator(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(camera.getLogin(), camera.getPassword().toCharArray());
}
})
.version(HttpClient.Version.HTTP_1_1)
.build();
由于我使用的是基本授权,因此我可以预先计算 auth 标头并将其存储在内部。并执行此代码,因为在日志中我可以看到以下内容:
2022-05-04 12:40:00.183 [TRACE] [pool-2-thread-78] Retrieving image from http://<censored>:7020/ISAPI/Streaming/channels/1/picture
2022-05-04 12:40:00.183 [TRACE] [pool-2-thread-78] Using authorization header of 'Basic <censored>'
2022-05-04 12:40:00.491 [ERROR] [pool-2-thread-78] Error retrieving image, status code is 401
但是,实际通过 TCP 发送的内容不包括授权标头。以下是来自 Wireshark 的“Follow TCP”转储:
GET /ISAPI/Streaming/channels/1/picture HTTP/1.1
Content-Length: 0
Host: <censored>:7020
User-Agent: Java-http-client/17.0.3
HTTP/1.1 401 Unauthorized
Date: Wed, 04 May 2022 12:39:59 GMT
Server: webserver
X-Frame-Options: SAMEORIGIN
Content-Length: 178
Content-Type: text/html
Connection: close
WWW-Authenticate: Digest qop="auth", realm="<censored>", nonce="<censored>", stale="FALSE"
<!DOCTYPE html>
<html><head><title>Document Error: Unauthorized</title></head>
<body><h2>Access Error: 401 -- Unauthorized</h2>
<p>Authentication Error</p>
</body>
</html>
我知道响应要求 Digest 授权,而我使用的是 Basic。这不是重点,相机也支持基本授权。关键是,“授权:”标头甚至没有随请求一起发送。
很难找到使用 Java17 原生 HttpClient 的任何好的指南,因为其中大部分都涵盖了 Apache 的。我从Baeldung 找到了一个,但它涵盖了 Java9。 JavaDoc 也没什么用。正如 Baeldung 所建议的,我也在使用 Authenticator,但它也没有启动。
我究竟做错了什么?
【问题讨论】:
标签: java http http-headers basic-authentication java-17