用于 Java 的 Azure SDK 中的 HTTP 客户端和管道

本文概述了如何在 Azure SDK for Java 中使用 HTTP 客户端和管道功能。 此功能为使用适用于 Java 库的所有 Azure SDK 的开发人员提供了一致、强大且灵活的体验。

HTTP 客户端

Azure SDK for Java 是使用 HttpClient 抽象实现的。 此抽象支持可插入的体系结构,该体系结构接受多个 HTTP 客户端库或自定义实现。 但是,为了简化大多数用户的依赖项管理,所有 Azure 客户端库都依赖于 azure-core-http-netty。 因此,Netty HTTP 客户端是所有用于 Java 库的 Azure SDK 中使用的默认客户端。

尽管 Netty 是默认 HTTP 客户端,但 SDK 提供了三个客户端实现,具体取决于项目中已有的依赖项。 这些实现适用于:

注意

JDK HttpClient 与 Azure SDK for Java 一起使用,仅支持 JDK 12 及更高版本。

替换默认 HTTP 客户端

如果更喜欢其他实现,可以通过在生成配置文件中排除它来删除对 Netty 的依赖项。 在 Maven pom.xml 文件中,排除 Netty 依赖项并包含另一个依赖项。

以下示例演示如何从 azure-security-keyvault-secrets 库的实际依赖项中排除 Netty 依赖项。 请务必从所有适当的 com.azure 库中排除 Netty,如下所示:

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-security-keyvault-secrets</artifactId>
    <version>4.2.2.</version>
    <exclusions>
      <exclusion>
        <groupId>com.azure</groupId>
        <artifactId>azure-core-http-netty</artifactId>
      </exclusion>
    </exclusions>
</dependency>

<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-core-http-okhttp</artifactId>
  <version>1.3.3</version>
</dependency>

注意

如果删除 Netty 依赖项但未就地提供任何实现,应用程序将无法启动。 类路径上必须存在 HttpClient 实现。

配置 HTTP 客户端

生成服务客户端时,默认使用 HttpClient.createDefault()。 此方法基于提供的 HTTP 客户端实现返回基本 HttpClient 实例。 如果需要更复杂的 HTTP 客户端(例如代理),每个实现都提供了一个生成器,可用于构造配置的 HttpClient 实例。 生成器是 NettyAsyncHttpClientBuilderOkHttpAsyncHttpClientBuilderJdkAsyncHttpClientBuilder

以下示例演示如何使用 Netty、OkHttp 和 JDK 11 HTTP 客户端生成 HttpClient 实例。 这些实例通过 http://localhost:3128 代理,使用用户 example 的密码 weakPassword进行身份验证。

// Netty
HttpClient httpClient = new NettyAsyncHttpClientBuilder()
    .proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 3128))
        .setCredentials("example", "weakPassword"))
    .build();

// OkHttp
HttpClient httpClient = new OkHttpAsyncHttpClientBuilder()
    .proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 3128))
        .setCredentials("example", "weakPassword"))
    .build();

// JDK 11 HttpClient
HttpClient client = new JdkAsyncHttpClientBuilder()
    .proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 3128))
        .setCredentials("example", "weakPassword"))
    .build();

现在可以将构造的 HttpClient 实例传递到服务客户端生成器中,以用作与服务通信的客户端。 以下示例使用新的 HttpClient 实例生成 Azure 存储 Blob 客户端。

BlobClient blobClient = new BlobClientBuilder()
    .connectionString(<connection string>)
    .containerName("container")
    .blobName("blob")
    .httpClient(httpClient)
    .build();

对于管理库,可以在管理器配置期间设置 HttpClient

AzureResourceManager azureResourceManager = AzureResourceManager.configure()
    .withHttpClient(httpClient)
    .authenticate(credential, profile)
    .withDefaultSubscription();

HTTP 管道

HTTP 管道是实现 Azure Java 客户端库中的一致性和可诊断性的关键组件之一。 HTTP 管道由以下组成:

  • HTTP 传输
  • HTTP 管道策略

创建客户端时,可以提供自己的自定义 HTTP 管道。 如果未提供管道,则客户端库将创建一个配置为与该特定客户端库一起使用的管道。

HTTP 传输

HTTP 传输负责建立与服务器的连接,以及发送和接收 HTTP 消息。 HTTP 传输构成了 Azure SDK 客户端库的网关,以便与 Azure 服务交互。 如本文前面所述,Azure SDK for Java 默认使用 Netty 进行 HTTP 传输。 但是,SDK 还提供可插入的 HTTP 传输,因此可以在适当的情况下使用其他实现。 SDK 还为 OkHttp 和 JDK 11 及更高版本随附的 HTTP 客户端提供了另外两个 HTTP 传输实现。

HTTP 管道策略

管道由为每个 HTTP 请求-响应往返执行的一系列步骤组成。 每个策略都有专用用途,并针对请求或响应执行操作,有时也可以同时执行这两项操作。 由于所有客户端库都有标准的“Azure Core”层,因此此层可确保每个策略在管道中按顺序执行。 发送请求时,策略将按将策略添加到管道的顺序执行。 收到来自服务的响应时,策略按相反的顺序执行。 在发送请求之前以及收到响应后,添加到管道的所有策略都会执行。 策略必须决定是否对请求做出反应、对响应做出反应,或者同时对两者做出反应。 例如,日志记录策略记录请求和响应,但身份验证策略仅对修改请求感兴趣。

Azure Core 框架为策略提供所需的请求和响应数据以及执行策略所需的任何上下文。 然后,该策略可以使用给定的数据执行其操作,并将该控件传递到管道中的下一个策略。

HTTP 管道关系图

HTTP 管道策略位置

向云服务发出 HTTP 请求时,处理暂时性故障和重试失败尝试非常重要。 由于此功能是常见的要求,Azure Core 提供了一个重试策略,可以监视暂时性故障并自动重试请求。

因此,此重试策略将整个管道拆分为两个部分:在重试策略之前执行的策略和重试策略之后执行的策略。 在重试策略之前添加的策略在每个 API 操作中只执行一次,重试策略后添加的策略执行次数与重试次数一样多。

因此,生成 HTTP 管道时,应了解是针对每个请求重试执行策略,还是为每个 API 操作执行一次策略。

常见的 HTTP 管道策略

基于 REST 的服务的 HTTP 管道具有用于身份验证、重试、日志记录、遥测和在标头中指定请求 ID 的策略的配置。 Azure Core 预加载了可添加到管道的这些常用 HTTP 策略。

政策 GitHub 链接
重试策略 RetryPolicy.java
身份验证策略 BearerTokenAuthenticationPolicy.java
日志记录策略 HttpLoggingPolicy.java
请求 ID 策略 RequestIdPolicy.java
遥测策略 UserAgentPolicy.java

自定义 HTTP 管道策略

HTTP 管道策略提供了一种方便的机制,用于修改或修饰请求和响应。 可以将自定义策略添加到用户或客户端库开发人员创建的管道。 将策略添加到管道时,可以指定是应按调用还是按重试执行此策略。

若要创建自定义 HTTP 管道策略,只需扩展基本策略类型并实现一些抽象方法。 然后,可以将策略插入管道。

HTTP 请求中的自定义标头

Azure SDK for Java 客户端库提供了一种通过公共 API 中的 Context 对象定义自定义标头的一致方法,如以下示例所示:

// Add your headers
HttpHeaders headers = new HttpHeaders();
headers.set("my-header1", "my-header1-value");
headers.set("my-header2", "my-header2-value");
headers.set("my-header3", "my-header3-value");

// Call API by passing headers in Context.
configurationClient.addConfigurationSettingWithResponse(
    new ConfigurationSetting().setKey("key").setValue("value"),
    new Context(AddHeadersFromContextPolicy.AZURE_REQUEST_HTTP_HEADERS_KEY, headers));

// The three headers are now be added to the outgoing HTTP request.

有关详细信息,请参阅 AddHeadersFromContextPolicy 类

默认 TLS/SSL 库

默认情况下,所有客户端库都使用 Tomcat 原生 Boring SSL 库,以实现原生级别的性能,用于 TLS/SSL 操作。 Boring SSL 库是一个 uber JAR,包含适用于 Linux、macOS 和 Windows 的本机库,与 JDK 中的默认 TLS/SSL 实现相比,可提供更好的性能。

减少 Tomcat-Native TLS/SSL 依赖项大小

默认情况下,Tomcat-Native Boring SSL 库的 uber JAR 用于 Java 的 Azure SDK。 要减小此依赖项的大小,你需要按照 netty-tcnative 的要求,包含具有 os 分类器的依赖项,如以下示例所示:

<project>
  ...
  <dependencies>
    ...
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-tcnative-boringssl-static</artifactId>
      <version>2.0.25.Final</version>
      <classifier>${os.detected.classifier}</classifier>
    </dependency>
    ...
  </dependencies>
  ...
  <build>
    ...
    <extensions>
      <extension>
        <groupId>kr.motd.maven</groupId>
        <artifactId>os-maven-plugin</artifactId>
        <version>1.4.0.Final</version>
      </extension>
    </extensions>
    ...
  </build>
  ...
</project>

使用 JDK TLS/SSL

如果你更愿意使用默认的 JDK TLS/SSL 而不是 Tomcat-Native Boring SSL,则需要排除 Tomcat 原生 Boring SSL 库。 请注意,根据我们的测试,JDK TLS/SSL 的性能比 Tomcat 原生 Boring SSL 慢 30%。 使用 com.azure:azure-core:1.28.0 或更高版本时,HttpClient实现库(例如 com.azure:azure-core-http-netty)负责管理对 Tomcat-Native Boring SSL 的依赖项。 若要排除依赖项,请将以下配置添加到 POM 文件:

<project>
  ...
  <dependencies>
    ...
    <dependency>
     <groupId>com.azure</groupId>
       <artifactId>azure-core-http-netty</artifactId>
       <version>1.13.6</version>
       <exclusions>
         <exclusion>
           <groupId>io.netty</groupId>
           <artifactId>netty-tcnative-boringssl-static</artifactId>
         </exclusion>
       </exclusions>
    </dependency>
    ...
  </dependencies>
  ...
</project>

后续步骤

熟悉 Azure SDK for Java 中的 HTTP 客户端功能后,了解如何进一步自定义所使用的 HTTP 客户端。 有关详细信息,请参阅 在 Azure SDK for Java中配置代理。