2. RESTful 接口定义规范与注解体系:@GET / @POST / @PUT / @DELETE、@Path、@Query、@Body

RESTful 风格是现代 API 设计的主流范式,Retrofit 通过注解将接口声明与 HTTP 请求无缝映射。本章围绕核心注解展开,解释每个注解的含义、适用场景以及如何在 Retrofit 中正确使用。

2.1 HTTP 方法与 Retrofit 注解对照

RESTful 规范使用 HTTP 动词表达资源操作:GET 查询、POST 创建、PUT 全量更新、DELETE 删除。Retrofit 提供同名注解,可附加 URL 路径。

HTTP 方法Retrofit 注解典型语义常用配合注解
GET@GET获取资源@Path、@Query、@QueryMap
POST@POST创建新资源@Body、@Field、@Part
PUT@PUT全量更新资源@Body、@Path
DELETE@DELETE删除资源@Path、@Query
规范提示: RESTful 要求 URL 使用名词复数形式,避免动词;如 /users/{id} 而非 /getUser。Retrofit 注解的 value 参数应与后端设计完全一致。

2.2 @Path:动态路径片段

将方法参数动态注入 URL 路径中,用 {参数名} 占位。适用于资源 ID、日期等可变部分。

public interface UserService {
    @GET("users/{id}")
    Call<User> getUserById(@Path("id") long userId);
}

运行时调用 getUserById(42) 会发起 GET /users/42 请求。

2.3 @Query:URL 查询参数

拼接在 ? 后的键值对,用于过滤、分页等。Retrofit 自动处理编码。

public interface UserService {
    @GET("users")
    Call<List<User>> getUsers(
        @Query("page") int page,
        @Query("size") int size,
        @Query("name") String name   // 可为 null,此时不拼接该参数
    );
}

调用 getUsers(1, 20, "Alice") 生成 GET /users?page=1&size=20&name=Alice。

2.4 @Body:请求体序列化

将对象自动序列化为 JSON(配合自定义 Converter)放入请求体。用于 POST/PUT 提交数据。

public interface UserService {
    @POST("users")
    Call<User> createUser(@Body User user);
}

Retrofit 通过注册的 GsonConverterFactory 或 MoshiConverterFactory 完成序列化。请求头中自动添加 Content-Type: application/json。

2.5 注解组合与参数位置

路径、查询、Body 可混合使用,但每个方法只能有一个 @Body。

@PUT("users/{id}")
Call<User> updateUser(
    @Path("id") long id,
    @Body User updatedUser
);

2.6 注解与接口定义映射流程

下图展示从 RESTful 资源定义到 Retrofit 注解声明的完整映射关系:

RESTful 资源 → Retrofit 注解映射流程 RESTful 资源端点 /users/{id} /users?page= HTTP 方法映射 @GET / @POST / @PUT / @DELETE 参数注解 @Path / @Query / @Body OkHttp 请求构建 URL拼接 + 序列化 + 头注入 网络执行 异步/同步 Call 响应反序列化 JSON → Java 对象 说明 1. @Path 必须与 URL 占位符一致 2. @Query 参数为 null 时自动忽略 3. @Body 只能有一个,由 Converter 序列化 4. 注解 value 可拼接常量路径 5. 可同时使用多个 @QueryMap 6. Retrofit 自动处理 URI 编码 7. 多个@Path按顺序替换

2.7 常见错误与调试

  • 路径占位符不匹配:@Path("id") 但 URL 中用 {userId} 会导致 IllegalArgumentException。务必保持 name 一致。
  • @Body 与 @Field 混用:两者不能共存于同一方法,@Field 用于表单(@FormUrlEncoded),@Body 用于 JSON。
  • @Query 参数未编码:Retrofit 默认使用 encoded = false 自动编码。若提前编码需 @Query(encoded = true)。
  • 注解 value 中路径末尾斜杠:建议统一以 / 结尾或都不要,避免拼接后出现双斜杠 //。
性能注意: 大量 @QueryMap 参数会生成冗长 URL,影响网络传输效率。建议将静态参数放入注解 value 中,仅动态参数使用 @Query。另外,@Body 序列化对象应避免过度嵌套,减少 JSON 体积。

2.8 调试最佳实践

在 OkHttp 日志拦截器中打印最终请求 URL 和 Body,确认注解拼接结果:

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(logging)
    .build();

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .client(client)
    .addConverterFactory(GsonConverterFactory.create())
    .build();

日志中可见 --> GET /users?page=1&size=20&name=Alice 等完整请求行,便于定位注解问题。