[APItest-Karate] HttpRequestBuilder | HttpClient发送请求
第3章:HTTP请求构建器
在第2章:场景引擎中,我们了解到ScenarioEngine
是一个勤勉的指挥者,负责协调单个测试场景中的所有步骤。
管理变量、应用配置并分发操作。其中最常见且强大的操作之一就是向应用程序的API发送HTTP请求。
但ScenarioEngine
在发送这些HTTP请求之前,是如何实际构建HTTP请求的呢?这就是**HTTP请求构建器(HttpRequestBuilder)**的职责所在
HTTP请求构建器解决了什么问题?
想象一下我们正在寄一封实体信件。在投递之前,我们需要仔细准备:
- 收件人地址(URL):信要寄到哪里?
- 方法(信件类型):是正式信件(POST)、便签(GET)、更新(PUT)还是取消(DELETE)?
- 内容(正文):要发送什么消息?
- 请求头(特殊说明):是否有"紧急"、"需要回执"或"内容是JSON"等特殊说明?
- 参数(额外细节):是否需要在地址中包含额外的细节,比如
trackingId
?
如果每次寄信都要手动完成这些步骤,不仅繁琐而且容易出错。HttpRequestBuilder
正是为了解决HTTP请求的这一问题而设计的。它是一个抽象层,帮助Karate以清晰、结构化的方式逐步构建HTTP请求,然后再发送出去。
它允许我们逐项指定请求的URL、方法、请求头、参数和正文。可以将其视为一个智能表单,我们为HTTP请求填写这个表单。表单中的每个字段都有明确定义,我们可以按任意顺序填写,确保最终的"信件"(HTTP请求)在发送前准备就绪。
构建请求:示例
让我们回顾第1章:特性文件中的"创建猫咪"场景,看看在编写测试步骤时,HttpRequestBuilder
是如何隐式工作的。
Scenario: 创建一只新猫# 步骤1:设置请求正文Given request { name: 'Whiskers', color: 'black' }# 步骤2:定义HTTP方法When method post# 步骤3:发送并检查响应Then status 200
在这些简单的Gherkin步骤背后,ScenarioEngine
正在使用HttpRequestBuilder
来逐步积累请求的所有细节:
Given request { name: 'Whiskers', color: 'black' }
:这一步告诉HttpRequestBuilder
准备一个包含此JSON数据的请求正文。When method post
:这一步告诉HttpRequestBuilder
请求将是一个POST
请求。Then status 200
:此时,HttpRequestBuilder
已经收集了所有信息。它"构建"最终的HttpRequest
对象,并将其交给HttpClient
实际发送
前文传送:
[Linux#57][HTTP] URL结构 | 原理 | 请求与响应 | postman | fiddler
[Linux#58][HTTP] 自己构建服务器 | 实现网页分离 | 设计思路
HttpRequestBuilder
的妙处在于,我们不需要在Gherkin测试中直接与其交互。我们使用Karate的关键字(url
、path
、request
、method
、header
、param
),而ScenarioEngine
会自动将这些关键字转换为对HttpRequestBuilder
的调用。
以下是不同Gherkin关键字如何参与构建请求:
Karate关键字 | 在HttpRequestBuilder上设置的内容 | 示例Gherkin |
---|---|---|
url | 请求的基础URL。 | * url 'https://api.example.com' |
path | 向URL添加路径段。 | Given path 'cats' |
method | HTTP方法(GET、POST、PUT、DELETE等)。 | When method post |
request | 请求的正文(JSON、XML、文本等)。 | Given request { id: 1 } |
header | 自定义HTTP请求头。 | And header Authorization = 'Bearer 123' |
param | URL中的查询参数。 | And param limit = 10 |
form field | 用于发送HTML表单数据。 | And form field name = 'Bob' |
内部机制:请求构建的过程
让我们深入了解一下HttpRequestBuilder
的内部工作原理。
当ScenarioEngine
(我们在第2章中提到的指挥者)遇到与构建HTTP请求相关的Gherkin步骤时,它不会立即发送请求。相反,它会使用HttpRequestBuilder
实例"记录"这些细节。这个HttpRequestBuilder
在单个请求的生命周期内存在,收集所有信息片段。
一旦遇到method
步骤(例如When method post
),它标志着请求已经完成并准备好发送。此时,HttpRequestBuilder
将所有收集到的细节"构建"成一个最终的、不可变的HttpRequest
对象。这个HttpRequest
对象随后被传递给HttpClient
,后者负责与API的实际通信。
以下是这一过程的简化序列:
HttpRequestBuilder
类
HttpRequestBuilder
是主要的类,用于保存请求的进行中细节。它提供了设置URL、方法、请求头、正文和参数的方法。它采用"流畅API"风格,意味着我们可以链式调用方法。
// karate-core/src/main/java/com/intuit/karate/http/HttpRequestBuilder.java
package com.intuit.karate.http;import com.intuit.karate.core.Config; // 用于全局设置public class HttpRequestBuilder {// 字段:存储正在构建的请求细节private String url;private String method;private Object body;// ... 其他字段,如请求头、参数等 ...public final HttpClient client; // 最终发送请求的客户端public HttpRequestBuilder(HttpClient client) {this.client = client;}public HttpRequestBuilder url(String value) {this.url = value; // 更新URLreturn this; // 返回'this'以支持方法链式调用}public HttpRequestBuilder method(String method) {this.method = method; // 设置HTTP方法return this;}public HttpRequestBuilder body(Object body) {this.body = body; // 设置请求正文return this;}// ... 其他方法,如header()、param()、path() ...public HttpRequest build() {// 在构建之前,确保设置默认值(例如,如果未指定方法,则默认为GET)// ... buildInternal()逻辑 ...HttpRequest request = new HttpRequest(); // 创建最终的HttpRequest对象request.setMethod(method);request.setUrl(getUri()); // 从基础URL、路径和参数构造完整URLrequest.setBody(com.intuit.karate.JsonUtils.toBytes(body)); // 将正文转换为字节// ... 设置请求头等 ...return request; // 返回完全构建的请求}public Response invoke() {// ScenarioEngine调用此方法实际发送请求return client.invoke(build()); // 构建请求,然后传递给HttpClient}// ... 其他内部方法 ...
}
说明:HttpRequestBuilder
类保存了HTTP请求的所有片段,这些片段在构建过程中逐步添加。
-
url()
、method()
和body()
等方法更新其内部状态 -
build()
方法获取所有这些积累的信息,并创建一个最终的HttpRequest
对象。 -
invoke()
方法是关键:它触发build()
,然后将生成的HttpRequest
传递给HttpClient
进行发送。
HttpRequest
类
HttpRequest
类表示最终、完整且不可变的HTTP请求,已准备好通过网络发送。
它是一个简单的数据容器,以结构化的方式保存所有必要的细节。
// karate-core/src/main/java/com/intuit/karate/http/HttpRequest.java
package com.intuit.karate.http;import java.util.List;
import java.util.Map;public class HttpRequest {private String url;private String method;private Map<String, List<String>> headers; // 存储所有请求头private byte[] body; // 将请求正文存储为字节// ... 所有字段的getter和setter ...public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}public byte[] getBody() {return body;}public void setBody(byte[] body) {this.body = body;}// ... 其他方法 ...
}
说明:HttpRequest
对象就像一封完美填写地址并包装好的信件。
-
它包含最终的URL、选择的HTTP方法、任何指定的请求头以及请求正文,一切都准备好交付。
-
它不包含任何构建自身的逻辑;它只是
HttpRequestBuilder
的最终产品。
HttpClient
接口
HttpClient
是一个接口,定义了如何发送HttpRequest
。
Karate提供了默认实现(如底层的HTTP客户端库),但理论上我们可以根据需要替换它。
// karate-core/src/main/java/com/intuit/karate/http/HttpClient.java
package com.intuit.karate.http;import com.intuit.karate.core.Config;public interface HttpClient {void setConfig(Config config);Config getConfig();Response invoke(HttpRequest request); // 核心方法:发送请求!}
说明:HttpClient
是投递服务。
-
一旦
HttpRequestBuilder
创建了HttpRequest
(信件),HttpClient.invoke()
(投递服务)就会将其发送到目标(API服务器)。 -
然后等待
Response
(回信)并将其带回Karate。
总结
HTTP请求构建器是Karate中一个强大组件,它简化了构建HTTP请求的复杂任务
- 通过理解Gherkin关键字(如
url
、method
、request
、header
和param
)如何通过HttpRequestBuilder
共同构建HttpRequest
对象,我们可以更深入地了解Karate如何有效地与API通信。
现在我们已经介绍了HTTP请求的构建和发送方式,我们可能会好奇Karate如何处理Gherkin步骤中的动态值
和表达式,比如评估response.id
或自定义JavaScript逻辑。
这正是我们将在下一章中探讨的内容:JS引擎(GraalVM)。