java http.HttpRequest不发送“授权:“报头-为什么?

toiithl6  于 2022-12-25  发布在  Java
关注(0)|答案(1)|浏览(187)

我正在尝试从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发送的内容不包括Authorization报头。以下是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>

我知道响应要求摘要授权,而我使用的是基本授权。这不是重点,相机也支持基本授权。重点是,"Authorization:"报头甚至没有随请求一起发送。
很难找到任何关于使用Java17原生HttpClient的好指南,因为大多数指南都涵盖了Apache。我在Baeldung中找到了一个,但它涵盖了Java9。JavaDoc也没有什么帮助。正如Baeldung建议的那样,我也在使用Authenticator,但它也不起作用。
我哪里做错了?

3mpgtkmj

3mpgtkmj1#

您没有做错什么。新的HttpClient似乎不支持摘要式身份验证。请参阅此处:https://bugs.openjdk.org/browse/JDK-8285888
建议的方法是自己在应用程序级别实现摘要身份验证。

相关问题