跳至主要內容

请求方法与标记注解

guodongAndroid大约 5 分钟

前言

上一篇文章 已过了差不多半年时间。之前我们学习了动态代理、泛型和反射的一些知识,那么本篇文章我们学习一下 Retrofit 中有哪些注解以及它们的作用,为我们后续正式学习 Retrofit 奠定基础。

注解类型

注解类型

如上图所示,Retrofit 中的注解主要分为以下三种类型:

  1. 请求方法相关的注解,
  2. 请求参数相关的注解,
  3. 标记类型相关的注解。

本篇文章我们主要学习请求方法与标记类型相关的注解。

请求方法注解

Retrofit 提供了 7种 常见的HTTP请求方法注解,分别是:

  1. GET请求:@GET
  2. POST请求:@POST
  3. PUT请求:@PUT
  4. DELETE请求:@DELETE
  5. PATCH请求:@PATCH
  6. HEAD请求:@HEAD
  7. OPTIONS请求:@OPTIONS

这几种请求注解都可以传入一个相对或绝对的路径,或者完整的URL来表示 endpoint,如 @GET 注解:

@GET("/foo")

endpoint:可以简单理解为HTTP请求地址,可以是相对路径,绝对路径,或者完整的URL地址。

@HTTP 注解有三个参数,一个必选参数,两个可选参数:

  1. method:HTTP请求方法,如:GET, POST等,必须大写,
  2. pathendpoint,同上面常见请求方法注解的参数,
  3. hasBody :是否有请求体,默认false,

可以替换上面7种请求注解,比如替换@GET注解:

@HTTP(method = "GET", path = "/foo", hasBody = false)

也支持其他的HTTP请求方法,比如TRACE请求方法:

@HTTP(method = "TRACE", path = "/foo", hasBody = false)

需要注意

  1. 如果我们定义的接口方法中的第一个参数被 @Url 注解标记,那么请求方法注解中的参数只能是默认值(即:空字符串),

  2. 有关 @Url 注解的使用,下篇文章我们再学习。

结合规则

我们知道 Retrofit 必须传入一个 baseUrl,否则会抛出异常,那么 baseUrlendpoint 之间是怎样的一种结合规则?

首先我们知道 baseUrl 必须以 / 结尾,

其次我们需要再明确下 endpoint 中什么是相对路径和绝对路径:如果 endpoint/ 开头,那么就是绝对路径,反之则是相对路径

  1. /foo/bar:是绝对路径,
  2. foo/bar:是相对路径

最后 baseUrlendpoint 之间的结合规则如下:

baseUrlendpointresult说明
http://example.com/api//foo/bar/http://example.com/foo/bar/绝对路径的endpoint仅会保留baseUrl中host部分,
忽略baseUrl中任何指定的路径
http://example.com/api/foo/bar/http://example.com/api/foo/bar/期望的请求地址
http://example.com/https://github.com/square/retrofit/https://github.com/square/retrofit/1.如果endpoint包含host,则替换baseUrl中的host,
2.如果endpoint包含scheme,也会替换baseUrl中的scheme
http://example.com///github.com/square/retrofit/http://github.com/square/retrofit/仅替换了baseUrl中的host,没有替换scheme

标记注解

@Tag

@Tag 注解标记HTTP接口方法中的参数,可以为每个HTTP请求增加一个标记,它的使用如下:

Call<ResponseBody> method(@Tag String tag);
request.tag(String.class);

Call<ResponseBody> method(@Tag List<String> tag);
request.tag(List.class)

@Tag 注解以参数的 class 类型为键,参数值为值进行存储,如果参数是泛型类型(参数化类型),则取它的原始类型为键。后续我们可以通过 Request.tag 方法获取设置的 Tag 值,比如可以在拦截器中获取进行一些特殊操作。

需要注意:

如果存在两个相同键值的 @Tag 会导致抛出异常:IllegalArgumentException(@Tag type java.lang.String is duplicate of parameter #1 and would always overwrite its value. (parameter #2) for method xxxxx)

@Streaming

@Streaming 注解标记HTTP接口方法,当接口方法的返回值类型为:ResponseBody时,返回原始的 ResponseBody 而不是 Retrofit 预读取/处理后的 ResponseBody

if (type == ResponseBody.class) {
    return Utils.isAnnotationPresent(annotations, Streaming.class)
        ? StreamingResponseBodyConverter.INSTANCE // 原始的ResponseBody
        : BufferingResponseBodyConverter.INSTANCE; // 预读取/处理的ResponseBody
}

需要注意:

如果我们使用了 @Streaming 注解,那么数据的读取以及读取过程中 socket 的一些异常就需要我们自己处理了。

@FormUrlEncoded

@FormUrlEncoded 注解标记HTTP接口方法,表示此HTTP请求体将使用表单URL编码,表单中的字段应声明为接口方法中的参数并使用 @Field@FieldMap 注解标记。

有关 @Field@FieldMap 注解的使用,下篇文章我们再学习。

需要注意:

  1. @FormUrlEncoded 注解标记的HTTP接口方法发出的请求中将会自动填充 application/x-www-form-urlencoded MIME 类型,并且字段名和值将在 URI 编码之前进行 UTF-8 编码(@Field@FieldMap 注解中的 encoded 属性为 false 时),
  2. @Field@FieldMap 注解仅能用于被 @FormUrlEncoded 注解标记的接口方法中,
  3. @FormUrlEncoded 注解标记的HTTP接口方法至少包含一个 @FeildFeildMap 注解标记的参数,
  4. @FormUrlEncoded 注解仅能标记带有请求体的HTTP请求方法,比如:@POST

@Multipart

@Multipart 注解标记HTTP接口方法,表示此HTTP请求体有多个部分,每个部分应声明为接口方法中的参数并使用 @Part@PartMap 注解标识。

有关 @Part@PartMap 注解的使用,下篇文章我们再学习。

需要注意:

  1. @Multipart 注解标注的HTTP接口方法发出的请求中将会自动填充 multipart/form-data MIME 类型,
  2. @Part@PartMap 注解仅能用于被 @Multipart 注解标记的接口方法中,
  3. @Multipart 注解标记的HTTP接口方法至少包含一个 @PartPartMap 注解标记的参数,
  4. @Multipart 注解仅能标记带有请求体的HTTP请求方法,比如:@POST

小结

  1. 一个HTTP接口方法中的参数不能同时存在两个及相同类型的 @Tag 注解,
  2. 一个HTTP接口方法不能同时被 @FormUrlEncoded@Multipart 注解标记,
  3. 一个HTTP接口方法中的参数不能同时存在 @Field@Part,或者 @FieldMap@Part,或者 @Field@PartMap,以及 @FileMap@PartMap
  4. 非必要尽量不要使用 @Streaming 注解。

总结

本文我们学习了 Retrofit 中关于请求方法和标记类型的注解以及它们的作用和一些使用注意事项,特别是我们对 baseUrlendpoint 结合规则的学习,对我们如何编写正确的接口方法提供了标准并起到了指导作用:

  1. 尽量使用相对路径来拼接完整请求地址
  2. 尽量使用统一的 baseUrl

希望可以帮你更好的使用 Retrofit。

那么,下篇再见啦,happy~