idtitlesidebar_label
http_body
HTTP Body
HTTP Body

POSTPUT等请求方法中,通常使用 HTTP 请求体进行传输数据。在 Forest 中有多种方式设置请求体数据。

@Body 注解

您可以使用@Body注解修饰参数的方式,将传入参数的数据绑定到 HTTP 请求体中。

@Body注解修饰的参数一定会绑定到请求体中,不用担心它会出现在其他地方

  1. /**
  2. * 默认body格式为 application/x-www-form-urlencoded,即以表单形式序列化数据
  3. */
  4. @Post(
  5. url = "http://localhost:8080/user",
  6. headers = {"Accept:text/plain"}
  7. )
  8. String sendPost(@Body("username") String username, @Body("password") String password);

表单格式

上面使用 @Body 注解的例子用的是普通的表单格式,也就是contentType属性为application/x-www-form-urlencoded的格式,即contentType不做配置时的默认值。

表单格式的请求体以字符串 key1=value1&key2=value2&...&key{n}=value{n} 的形式进行传输数据,其中value都是已经过 URL Encode 编码过的字符串。

  1. /**
  2. * contentType属性设置为 application/x-www-form-urlencoded 即为表单格式,
  3. * 当然不设置的时候默认值也为 application/x-www-form-urlencoded, 也同样是表单格式。
  4. * 在 @Body 注解的 value 属性中设置的名称为表单项的 key 名,
  5. * 而注解所修饰的参数值即为表单项的值,它可以为任何类型,不过最终都会转换为字符串进行传输。
  6. */
  7. @Post(
  8. url = "http://localhost:8080/user",
  9. contentType = "application/x-www-form-urlencoded",
  10. headers = {"Accept:text/plain"}
  11. )
  12. String sendPost(@Body("key1") String value1, @Body("key2") Integer value2, @Body("key3") Long value3);

调用后产生的结果可能如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/x-www-form-urlencoded
  4. BODY:
  5. key1=xxx&key2=1000&key3=9999

@Body注解修饰的参数为一个对象,并注解的value属性不设置任何名称的时候,会将注解所修饰参数值对象视为一整个表单,其对象中的所有属性将按 属性名1=属性值1&属性名2=属性值2&...&属性名{n}=属性值{n} 的形式通过请求体进行传输数据。

  1. /**
  2. * contentType 属性不设置默认为 application/x-www-form-urlencoded
  3. * 要以对象作为表达传输项时,其 @Body 注解的 value 名称不能设置
  4. */
  5. @Post(
  6. url = "http://localhost:8080/hello/user",
  7. headers = {"Accept:text/plain"}
  8. )
  9. String send(@Body User user);

调用后产生的结果如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/x-www-form-urlencoded
  4. BODY:
  5. username=foo&password=bar

JSON格式: @JSONBody注解修饰对象

发送JSON非常简单,只要用@JSONBody注解修饰相关参数就可以了,该注解自1.5.0-RC1版本起可以使用。 使用@JSONBody注解的同时就可以省略 contentType = “application/json”属性设置。

  1. /**
  2. * 被@JSONBody注解修饰的参数会根据其类型被自定解析为JSON字符串
  3. * 使用@JSONBody注解时可以省略 contentType = "application/json"属性设置
  4. */
  5. @Post("http://localhost:8080/hello/user")
  6. String helloUser(@JSONBody User user);

调用后产生的结果如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/json
  4. BODY:
  5. {"username": "foo", "password": "bar"}

JSON格式: @JSONBody注解修饰键值对

@JSONBody注解可以按键值对拆分成多个参数进行传入,在发送的时候再合成一个完成的JSON字符串:

  1. /**
  2. * 按键值对分别修饰不同的参数
  3. * 这时每个参数前的 @JSONBody 注解必须填上 value 属性或 name 属性的值,作为JSON的字段名称
  4. */
  5. @Post("http://localhost:8080/hello/user")
  6. String helloUser(@JSONBody("username") String username, @JSONBody("password") String password);

如调用helloUser("foo", "bar");会产生如下结果:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/json
  4. BODY:
  5. {"username": "foo", "password": "bar"}

JSON格式: @JSONBody注解修饰集合对象

@JSONBody注解也支持Map、List等集合类型参数

  1. /**
  2. * 被@JSONBody注解修饰的Map类型参数会被自定解析为JSON字符串
  3. */
  4. @Post(url = "http://localhost:8080/hello/user")
  5. String helloUser(@JSONBody Map<String, Object> user);

若调用代码如下:

  1. Map<String, Object> map = new HashMap<>();
  2. map.put("name", "foo");
  3. map.put("password", "bar");
  4. client.helloUser(map);

会产生如下结果:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/json
  4. BODY:
  5. {"username": "foo", "password": "bar"}

List等列表对象也同理:

  1. /**
  2. * 被@JSONBody注解修饰的List类型参数会被自定解析为JSON字符串
  3. */
  4. @Post(url = "http://localhost:8080/hello/user-names")
  5. String helloUserNames(@JSONBody List<String> usernames);

若调用代码如下:

  1. List<String> names = Lists.newArrayList("A", "B", "C");
  2. client.helloUserNames(names);

会产生如下结果:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/json
  4. BODY:
  5. ["A", "B", "C"]

JSON格式: @JSONBody注解修饰字符串

@JSONBody注解还支持字符串类型参数,可以直接传入一个JSON字符串进行传输

  1. /**
  2. * 直接修饰一个JSON字符串
  3. */
  4. @Post("http://localhost:8080/hello/user")
  5. String helloUser(@JSONBody String userJson);

JSON格式: @Body注解 + contentType

除了@JSONBody注解,使用@Body注解也可以,只要将contentType属性或Content-Type请求头指定为application/json便可。

  1. @Post(
  2. url = "http://localhost:8080/hello/user",
  3. contentType = "application/json"
  4. )
  5. String send(@Body User user);

调用后产生的结果如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/json
  4. BODY:
  5. {"username": "foo", "password": "bar"}

XML格式: @XMLBody注解修饰对象

发送XML也非常简单,只要用@XMLBody注解修饰相关参数就可以了,该注解自1.5.0-RC1版本起可以使用。

  1. /**
  2. * 被@JSONBody注解修饰的参数会根据其类型被自定解析为XML字符串
  3. * 其修饰的参数类型必须支持JAXB,可以使用JAXB的注解进行修饰
  4. * 使用@XMLBody注解时可以省略 contentType = "application/xml"属性设置
  5. */
  6. @Post("http://localhost:8080/hello/user")
  7. String sendXmlMessage(@XMLBody User user);

要注意的是,这里的User对象要绑定JAXB注解:

  1. @XmlRootElement(name = "misc")
  2. public User {
  3. private String usrname;
  4. private String password;
  5. public String getUsername() {
  6. return username;
  7. }
  8. public void setUsername(String username) {
  9. this.username = username;
  10. }
  11. public String getPassword() {
  12. return password;
  13. }
  14. public void setPassword(String password) {
  15. this.password = password;
  16. }
  17. }

调用传入User对象后的结果如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/xml
  4. BODY:
  5. <misc><username>foo</username><password>bar</password></misc>

XML格式: @XMLBody注解修饰字符串

@XMLBody支持的另一种形式就是直接传入一个XML字符串

  1. /**
  2. * @XMLBody注解可以修饰一个字符串参数,作为要传输的XML字符串
  3. */
  4. @Post("http://localhost:8080/hello/user")
  5. String sendXmlMessage(@XMLBody String userXml);

XML格式: @Body注解 + contentType + filter

使用@Body注解发送XML数据较为特殊,除了指定contentType属性或Content-Type请求头为application/xml外,还需要设置@Bodyfilter属性为xml

  1. @Post(
  2. url = "http://localhost:8080/hello/user",
  3. contentType = "application/xml"
  4. )
  5. String send(@Body(filter = "xml") User user);

调用传入User对象后的结果如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/xml
  4. BODY:
  5. <misc><username>foo</username><password>bar</password></misc>

data 属性

您也可以通过@Request、以及@Get@Post等请求注解的data属性把数据添加到请求体。需要注意的是只有当typePOSTPUTPATCH这类 HTTP Method 时,data属性中的值才会绑定到请求体中,而GET请求在有些情况会绑定到url的参数中。

具体type属性和data属性数据绑定位置的具体关系如下表:

typedata属性数据绑定位置支持的contentTypeContent-Type请求头
GETurl参数部分只有application/x-www-form-urlencoded
POST请求体任何contentType
PUT请求体任何contentType
PATCH请求体任何contentType
HEADurl参数部分只有application/x-www-form-urlencoded
OPTIONSurl参数部分只有application/x-www-form-urlencoded
DELETEurl参数部分只有application/x-www-form-urlencoded
TRACEurl参数部分只有application/x-www-form-urlencoded

data属性在POST请求中绑定请求体

  1. public interface MyClient {
  2. @Request(
  3. url = "http://localhost:8080/hello/user",
  4. type = "post",
  5. data = "username=foo&password=bar",
  6. headers = {"Accept:text/plain"}
  7. )
  8. String dataPost();
  9. }

该接口调用后所实际产生的 HTTP 请求如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Accept:text/plain
  4. BODY:
  5. username=foo&password=bar

data属性中进行数据绑定:

  1. public interface MyClient {
  2. /**
  3. * 这里 data 属性中设置的字符串内容会绑定到请求体中
  4. * 其中 ${0} 和 ${1} 为参数序号绑定,会将序号对应的参数绑定到字符串中对应的位置
  5. * ${0} 会替换为 username 的值,${1} 会替换为 password 的值
  6. */
  7. @Request(
  8. url = "http://localhost:8080/hello/user",
  9. type = "post",
  10. data = "username=${0}&password=${1}",
  11. headers = {"Accept:text/plain"}
  12. )
  13. String dataPost(String username, String password);
  14. }

:::info 提示 其中${数字}的语法用到了《参数序号引用》 :::

如果调用方代码如下所示:

  1. myClient.dataPost("foo", "bar");

实际产生的 HTTP 请求如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Accept: text/plain
  4. BODY:
  5. username=foo&password=bar

您可以直接把 JSON 数据加入到请求体中,其中header设置为Content-Type: application/json

  1. public interface MyClient {
  2. @Request(
  3. url = "http://localhost:8080/hello/user",
  4. type = "post",
  5. data = "{\"username\": \"${0}\", \"password\": \"${1}\"}",
  6. headers = {"Content-Type: application/json"}
  7. )
  8. String postJson(String username, String password);
  9. }

如果调用方代码如下所示:

  1. myClient.postJson("foo", "bar");

实际产生的 HTTP 请求如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/json
  4. BODY:
  5. {"username": "foo", "password": "bar"}

把 XML 数据加入到请求体中,其中header设置为Content-Type: application/json

  1. public interface MyClient {
  2. @Request(
  3. url = "http://localhost:8080/hello/user",
  4. type = "post",
  5. data = "<misc><username>${0}</username><password>${1}</password></misc>",
  6. headers = {"Content-Type: application/xml"}
  7. )
  8. String postXml(String username, String password);
  9. }

如果调用方代码如下所示:

  1. myClient.postXml("foo", "bar");

实际产生的 HTTP 请求如下:

  1. POST http://localhost:8080/hello/user
  2. HEADER:
  3. Content-Type: application/xml
  4. BODY:
  5. <misc><username>foo</username><password>bar</password></misc>