🍭 请求头
在《构建接口》的例子中,我们已经知道了可以通过@Request
注解的headers
属性设置一条 HTTP 请求头。
现在我们来看看如何添加多条请求头。
# headers属性
其中headers
属性接受的是一个字符串数组,在接受多个请求头信息时以以下形式填入请求头:
{
"请求头名称1: 请求头值1",
"请求头名称2: 请求头值2",
"请求头名称3: 请求头值3",
...
}
2
3
4
5
6
其中组数每一项都是一个字符串,每个字符串代表一个请求头。请求头的名称和值用:
分割。
具体代码请看如下示例:
public interface MyClient {
@Request(
url = "http://localhost:8080/hello/user",
headers = {
"Accept-Charset: utf-8",
"Content-Type: text/plain"
}
)
String multipleHeaders();
}
2
3
4
5
6
7
8
9
10
11
该接口调用后所实际产生的 HTTP 请求如下:
GET http://localhost:8080/hello/user
HEADER:
Accept-Charset: utf-8
Content-Type: text/plain
如果要每次请求传入不同的请求头内容,可以在headers
属性的请求头定义中加入数据绑定
。
public interface MyClient {
@Request(
url = "http://localhost:8080/hello/user",
headers = {
"Accept-Charset: ${encoding}",
"Content-Type: text/plain"
}
)
String bindingHeader(@Var("encoding") String encoding);
}
2
3
4
5
6
7
8
9
10
11
如果调用方代码如下所示:
myClient.bindingHeader("gbk");
这段调用所实际产生的 HTTP 请求如下:
GET http://localhost:8080/hello/user
HEADER:
User-Agent: forest/1.5.36
Accept-Charset: gbk
Content-Type: text/plain
# User-Agent 请求头
其中, User-Agent
是特殊的通用请求头,所有的 Forest 请求都会默认自动加上User-Agent: forest/{version}
这样的请求头。
该请求头无法删除,但可以用其他的值来覆盖
@Request(
url = "http://localhost:8080/hello/user",
headers = {
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)",
"Accept-Charset: ${encoding}",
"Content-Type: text/plain"
}
)
String bindingHeader(@Var("encoding") String encoding);
2
3
4
5
6
7
8
9
若被覆盖,则User-Agent
请求头的值就会自定义的User-Agent
内容
# @Header 注解
想必大家都已经了解通过 headers
属性设置请求头的方法了。不过这种方式虽然直观,但如要没通过参数传入到请求头中就显得比较啰嗦了。
所以Forest还提供了 @Header
注解来帮助您把方法的参数直接绑定到请求体中。
/**
* 使用 @Header 注解将参数绑定到请求头上
* @Header 注解的 value 指为请求头的名称,参数值为请求头的值
* @Header("Accept") String accept将字符串类型参数绑定到请求头 Accept 上
* @Header("accessToken") String accessToken将字符串类型参数绑定到请求头 accessToken 上
*/
@Post("http://localhost:8080/hello/user?username=foo")
void postUser(@Header("Accept") String accept, @Header("accessToken") String accessToken);
2
3
4
5
6
7
8
9
10
如果有很多很多的请求头要通过参数传入,我需要定义很多很多参数吗?当然不用!
/**
* 使用 @Header 注解可以修饰 Map 类型的参数
* Map 的 Key 指为请求头的名称,Value 为请求头的值
* 通过此方式,可以将 Map 中所有的键值对批量地绑定到请求头中
*/
@Post("http://localhost:8080/hello/user?username=foo")
void headHelloUser(@Header Map<String, Object> headerMap);
/**
* 使用 @Header 注解可以修饰自定义类型的对象参数
* 依据对象类的 Getter 和 Setter 的规则取出属性
* 其属性名为 URL 请求头的名称,属性值为请求头的值
* 以此方式,将一个对象中的所有属性批量地绑定到请求头中
*/
@Post("http://localhost:8080/hello/user?username=foo")
void headHelloUser(@Header MyHeaderInfo headersInfo);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
注意
(1) 需要单个单个定义请求头的时候,@Header注解的value值一定要有,比如 @Header("Content-Type") String contentType
(2) 需要绑定对象的时候,@Header注解的value值一定要空着,比如 @Header MyHeaders headers 或 @Header Map headerMap
# 别名与顺序
使用自定义类型作为请求头参数时,往往会碰到要发送的字段名、顺序和 Java 类中的字段名、顺序不同的情况,对于此类问题请参见《对象字段》
# 延迟请求头参数
延迟请求头参数 (也称作 Lambda 请求头参数),在您需要不马上求值的情况使用。
有很多情况,请求头的参数值不能马上得出,而是在请求发送前的那一刻(所有请求参数都到位时)才能得出,典型的例子就是加签验证的场景
// 使用 Lazy 作为 Query 的参数类型
@Post("/data")
String sendData(@Body data, @Header("token") Lazy<String> token);
2
3
在调用的时候,传入 Lambda
myClient.sendData("Foo", "Bar", req -> {
// req 为请求对象
// 返回值将作为参数值添加到请求头中
return "";
});
2
3
4
5
在 Lambda 代码块中可以调用req.body().encodeToString()
将整个请求体的数据序列化为字符串
// Lambda 的参数为 ForestRequest 请求对象
// 调用 req.body().encodeString() 可以立即将整个请求体的数据序列化为字符串
// encrypt 是自定义的加密方法
myClient.sendData("Foo", "Bar", req -> encrypt(req.body().encodeToString()));
2
3
4