跳至主要內容

请求参数注解(一)

guodongAndroid大约 5 分钟

前言

在上一篇文章 请求方法与标记注解 中我们学习了 Retrofit 中的HTTP请求方法注解和标记类型注解,那么本篇文章我们先学习 Retrofit 中的 @Url@Path 请求参数注解。

@Url

@Url 注解标记HTTP接口方法的一个参数,表示这个参数是一个 endpoint,可以与 baseUrl 进行结合,根据上一篇文章中描述的结合规则拼接完整的HTTP请求地址,简单使用示例如下:

interface Service {
	@GET
	Call<ResponseBody> method(@Url String url);
}

// 假设 baseUrl 如下:
// baseUrl = "http://example.com/"
Service service = retrofit.create(Service.class);
service.method("foo/bar/");

// 那么完整的请求地址如下:
// request.url().toString(): http://example.com/foo/bar/

@Url 注解使用时有以下几点需要注意:

  1. @Url 注解标记的参数必须在 @Query@QueryName@QueryMap 注解标记参数的前面,否则抛出异常,所以通常标记第一个参数,下面是错误示例:

    // 错误示例
    interface Service {
    	@GET
    	Call<ResponseBody> method(@Query("ping") String ping, @Url String url);
    }
    
  2. @Url 注解标记的参数必须是以下几种类型之一:

    1. java.lang.String
    2. okhttp3.HttpUrl
    3. java.net.URI
    4. android.net.Uri
  3. 如果请求方法注解中的 endpoint 不是默认值(即:空字符串),则会抛出异常,即:@Url 注解标记的 endpoint 不能与请求方法注解中的 endpoint 共存,下面是错误示例:

    // 错误示例
    interface Service {
    	@GET("foo/bar/")	// 请求方法注解中的 endpoint 不是默认值(即:空字符串)
    	Call<ResponseBody> method(@Url String url);
    }
    
    Service service = retrofit.create(Service.class);
    service.method("foo/bar/");
    
  4. 如果使用了 @Url 注解,那么就不能再使用 @Path 注解,即 @Url 注解和 @Path 注解存在互斥关系,否则抛出异常,

  5. 一个HTTP接口方法中不能同时存在两个及以上的 @Url 注解,否则抛出异常,

@Path

@Path 注解标记HTTP接口方法的一个参数,表示这个参数用于替换HTTP请求注解静态路径段中的命名路径。注解的值会经过 Retrofit#stringConverter(Type, Annotation[]) 转换,如果没有找到匹配的字符串转换器则使用 Object#toString(),最后再经过URL编码。

@Path 注解有两个参数,分别为:

  1. value:对应路径段中的命名路径,
  2. encoded:当前参数值是否已经经过URL编码,为 true 的话,Retrofit 内部不会再经过URL编码,默认 false

简单使用示例如下:

interface Service {
	@GET("image/{id}")
	Call<ResponseBody> method(@Path("id") String id);
}

// 假设 baseUrl 如下:
// baseUrl = "http://example.com/"
Service service = retrofit.create(Service.class);
service.method("1");

// 那么完整的请求地址如下:
// request.url().toString(): http://example.com/image/1

// ========================================================================
// encoded
interface Service {
	@GET("user/{name}")
	Call<ResponseBody> method(@Path("name") String name);
}

service.method("guodong+Android");
// url: user/guodong%2BAndroid

// ========================================================================
// not encoded
interface Service {
	@GET("user/{name}")
	Call<ResponseBody> method(@Path(value = "name", encoded = true) String name);
}

service.method("guodong+Android");
// url: user/guodong+Android

@Path 注解使用时有以下几点需要注意:

  1. @Path 注解标记的参数必须在 @Query@QueryName@QueryMap 注解标记参数的前面,否则抛出异常,这一点与 @Url 注解类似,
  2. 如果使用了 @Path 注解,那么就不能再使用 @Url 注解,即 @Url 注解和 @Path 注解存在互斥关系,否则抛出异常,
  3. 基于第2条的限制条件,@Path 注解仅能和HTTP请求方法注解中的 endpoint 配套使用,
  4. @Path 注解可以存在多个,但必须有与之对应的命名路径,否则抛出异常,
  5. @Path 注解标记的参数的值不能包含路径遍历字符:...%2e 以及 %2E

作用

前面我们学习了 @Url@Path 请求参数注解的简单使用与注意事项,现在我们总结一下它俩各自的作用或者说它俩可以解决什么样的问题。

@Url

我们平常的工作中可能很少使用 @Url 注解:

  1. 可能是因为我们的接口地址都可以写在HTTP请求方法注解中,
  2. 可能是因为我们还没有遇到使用 @Url 注解的场景,
  3. 还可能是因为我们不了解 @Url 注解的作用,

但是我们不能小看这个注解,在某些方面这个注解的作用还是非常大的。

那么,@Url 注解到底有什么作用呢?或者说相对于HTTP请求方法注解,它有什么优势?可以解决什么问题?

不知道读者是否遇到过以下几个场景,比如:

  1. 请求接口地址是由服务端返回的,
  2. 请求接口地址是由外部服务商提供的,不能遵循 baseUrl 的结合规则,
  3. 请求接口地址有多个版本,客户端需要做兼容时:
    1. v1/user/name
    2. v2/user/name

从以上几个场景可以看出,请求地址大部分是不固定的,或者说是动态的,这时候HTTP请求注解中的静态请求路径已不再适用,那么以上几个场景中的问题就都可以使用 @Url 注解来解决了。

@Url 注解非常适合动态请求路径的场景。

Retrofit 为我们提供了两种请求路径的方式:

  1. HTTP请求方法注解中的静态请求路径,
  2. @Url 注解的动态请求路径,

由于是动态请求路径,所以 @Url 注解比较适合 GET 请求,或者简单的 POST 请求。

@Path

@Path 注解在平常的工作中使用频率应该是非常高的,它非常适用于 RESTful 风格的 API 接口,它的作用就是替换HTTP请求注解静态路径段中的命名路径。

同时,它也为HTTP请求方法注解静态请求路径增强了部分动态特性。

总结

本文学习了 @Url@Path 请求参数注解的简单使用与注意事项,以及各自的作用。这两个注解都参与了解析完整URL地址的逻辑,是非常重要的两个注解。

通过本文的学习,让我们在实际的工作中对这两个注解的使用更加的得心应手。

希望可以帮你更好的使用 Retrofit,happy~