注解详解:@GET、@POST、@PUT、@DELETE、@HTTP 的使用场景
说实话,刚用 Retrofit 那会儿,我也老搞混这些注解。不就是 HTTP 方法嘛,但实际项目中踩了几次坑才明白——选对注解,写出来的接口才干净、好维护。今天我把它们掰开揉碎了讲,你跟着走一遍就清楚了。
1. @GET —— 取数据,不折腾
@GET 最常用,对应 HTTP GET 请求。说白了就是“向服务器要东西”,参数通常拼在 URL 里或通过 @Query 传。
典型使用:获取用户列表、查询订单详情、搜索商品。
public interface ApiService {
@GET("users")
Call<List<User>> getUsers();
// 带查询参数
@GET("users/search")
Call<List<User>> searchUsers(@Query("name") String name,
@Query("page") int page);
}
我的习惯:我喜欢把查询参数单独用 @QueryMap 封装起来,接口签名更清爽,尤其参数多的时候。
之前在做一个新闻客户端,首页接口用 @GET 拉栏目列表。结果 QA 反馈偶尔刷不出数据,查了半天才发现是参数名拼写错误——URL 上的参数名必须和后端约定的一模一样,大小写都敏感。嗯,从那以后我都用 @QueryMap 统一管理,再也不手写逐个参数了。
2. @POST —— 新增一条记录
@POST 用于创建资源。请求体里传数据,服务器返回创建成功的标识(通常是 ID 或完整对象)。
@POST("users")
Call<User> createUser(@Body User user);
避坑:我曾经以为 @Body 会自动忽略 null 字段,结果发现它序列化时会带上。如果后端对 null 敏感,建议配合 @JsonInclude(Include.NON_NULL) 使用。
还有,别在 @POST 里拼 URL 参数。有些新人会把查询参数也塞进 URL,看起来像 @POST("users?source=app")。这样虽然能跑,但语义不对——创建操作应该把非体量参数用 @Query 或 @Header 传,别混着用。
3. @PUT —— 全量替换
@PUT 是全量更新。你传什么,服务器就把整个资源替换成什么。如果只传了部分字段,没传的会被清空(取决于后端实现)。
@PUT("users/{id}")
Call<User> updateUser(@Path("id") int userId, @Body User user);
重点:@PUT 不是“修改个别字段”,而是“用新对象整体覆盖旧对象”。很多人搞混这个,项目里出过好几次数据丢失事故。
我记得有次做后台管理系统,同事把 @PUT 当补丁用,只传了几个字段。结果用户头像全部变成默认——因为没传头像字段,服务器直接覆盖成 null。那以后我们规定:部分更新必须用 @PATCH(虽然 Retrofit 不内置,但 @HTTP 可以搞定)。
4. @DELETE —— 删了就别想找回来
@DELETE 语义最明确,删除指定资源。通常只需要传个 ID。
@DELETE("users/{id}")
Call<ResponseBody> deleteUser(@Path("id") int userId);
小技巧:返回类型我习惯用 Call<ResponseBody>,因为删除成功一般只关心状态码,不需要解析 body。
有个细节:某些服务端删除接口要求传请求体(比如软删除时带备注)。这时候 @DELETE 可以搭配 @Body 吗?理论上 OK,但 Retrofit 默认的 DELETE 会忽略 body。我遇到过这种情况,最终用 @HTTP 自定义解决了——往下看。
5. @HTTP —— 万能自定义工具
@HTTP 是 Retrofit 最后一张牌。当标准注解搞不定时,就用它。
// 自定义 DELETE 带 Body
@HTTP(method = "DELETE", path = "users/{id}", hasBody = true)
Call<ResponseBody> deleteUserWithBody(@Path("id") int userId,
@Body DeleteRequest body);
// 自定义 PATCH(部分更新)
@HTTP(method = "PATCH", path = "users/{id}", hasBody = true)
Call<User> patchUser(@Path("id") int userId, @Body Map<String, Object> fields);
// 自定义 HEAD
@HTTP(method = "HEAD", path = "version", hasBody = false)
Call<Void> checkVersion();
适用场景:
- 需要
PATCH方法时 - 标准注解不允许添加请求体时(比如
@DELETE加 body) - 非标准 HTTP 方法(如
MOVE、COPY)
曾经踩过的坑:我之前在对接第三方支付 API 时,对方要求用 PURGE 方法清缓存。Retrofit 没有这个注解,当时差点用 @POST 冒充。后来用 @HTTP(method = "PURGE", ...) 完美解决。所以遇到奇葩方法,别硬套,直接用 @HTTP 自定义。
6. 快速指南:如何挑选注解
下面这个表是我自己总结的,你可以直接收藏当参考。
| 注解 | HTTP 方法 | 核心用途 | 请求体 | 幂等 |
|---|---|---|---|---|
| @GET | GET | 查询/读取资源 | 否 | 是 |
| @POST | POST | 创建资源 | 是 | 否 |
| @PUT | PUT | 全量更新/替换 | 是 | 是 |
| @DELETE | DELETE | 删除资源 | 通常无 | 是 |
| @HTTP | 自定义 | 非标准方法/PATCH/带体DELETE | 可配 | 看实现 |
一句话口诀:取用GET,建用POST,全改PUT,删用DELETE,特殊走 @HTTP。
这五个注解覆盖了 99% 的日常需求。你写接口时多想想:我这次操作是“查”还是“改”?是全量还是部分?想清楚了,注解选起来就很简单。嗯,今天就到这,下回见。