【问题标题】:java.net.http.HttpRequest not sending "Authorization:" header - why?java.net.http.HttpRequest 不发送“授权:”标头 - 为什么?
【发布时间】: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


    【解决方案1】:

    你没有做错任何事。似乎新的 HttpClient 不支持开箱即用的摘要身份验证。看这里:https://bugs.openjdk.org/browse/JDK-8285888

    建议的方法是在应用程序级别自己实现摘要身份验证。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-28
      • 1970-01-01
      • 1970-01-01
      • 2018-02-04
      • 2020-05-22
      • 2019-04-20
      • 1970-01-01
      • 2017-12-04
      相关资源
      最近更新 更多