Retrofit传参为Json的多种实现方式与场景区分
在Android开发中,Retrofit作为最受欢迎的网络请求库,以其简洁的API设计和灵活的配置方式广受开发者青睐,在实际项目中,我们经常需要将参数以Json格式传递给服务器,但Retrofit提供了多种传参方式(如@Field、@Part、@Body等),如何准确区分并选择适合Json传参的方式,是开发者必须的技能,本文将详细解析Retrofit中Json传参的实现逻辑,并通过对比不同注解的适用场景,帮助开发者快速“如何传参为Json”的核心要点。
Retrofit传参的核心逻辑:注解与数据转换
Retrofit本身不处理数据序列化,而是通过Converter(如Gson、Jackson、Moshi)将Java对象转换为Json字符串,或反向解析Json响应,传参为Json的关键在于:选择正确的注解标记参数,并配置对应的Converter,Retrofit默认不包含Converter,需在初始化时添加依赖,
// 使用GsonConverter implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
Json传参的常见方式与注解对比
@Body:直接传递Java对象(最常用)
适用场景:当需要传递一个复杂的Json对象(如嵌套对象、数组)时,@Body是最直接的方式,Retrofit会通过Converter将传入的Java对象自动序列化为Json字符串,并作为请求体(Request Body)发送。
实现方式:
- 定义请求参数的Java模型类(需与Json结构对应)。
- 在接口方法中使用
@Body注解标记参数。
示例:
// 定义请求参数模型
public class UserRequest {
private String name;
private int age;
private List<String> hobbies;
// 构造方法、getter/setter省略
}
// 接口定义
@POST("/api/user")
Call<UserResponse> createUser(@Body UserRequest request);
// 调用示例
UserRequest request = new UserRequest("张三", 25, Arrays.asList("篮球", "阅读"));
Call<UserResponse> call = apiService.createUser(request);
关键点:
@Body只能用于@POST、@PUT、@PATCH等支持请求体的HTTP方法。- 参数必须是Java对象(非基本类型、非Map/键值对形式),Retrofit通过Converter将其转为Json。
@Field + @FormUrlEncoded:键值对Json(适用于简单表单)
适用场景:当服务器要求以application/x-www-form-urlencoded格式传递参数,且需要将多个键值对组合成Json字符串时(例如某些旧接口)。
实现方式:
- 使用
@FormUrlEncoded标记接口方法,表示表单编码。 - 通过
@Field标记每个参数,Retrofit会将参数拼接为key1=value1&key2=value2格式,若需Json格式,需手动拼接Json字符串作为@Field的值。
示例:
@FormUrlEncoded
@POST("/api/login")
Call<LoginResponse> login(
@Field("user_info") String userInfoJson // 手动拼接Json字符串
);
// 调用示例:手动构造Json字符串
String userInfoJson = "{\"username\":\"admin\",\"password\":\"123456\"};
Call<LoginResponse> call = apiService.login(userInfoJson);
局限性:
- 需手动构造Json字符串,无法直接传递Java对象,易出错且维护性差。
- 仅适用于表单编码场景,若服务器要求原生Json请求体(
application/json),此方式不适用。
@Part + @Multipart:文件上传+Json混合场景
适用场景:同时上传文件和Json参数时(如头像上传+用户信息更新)。@Part支持将Java对象通过Converter转为Json,并作为 multipart 表单的一部分发送。
实现方式:
- 使用
@Multipart标记接口方法,表示multipart请求。 - 通过
@Part标记参数,需指定MediaType为application/json。
示例:
@Multipart
@POST("/api/user/avatar")
Call<UploadResponse> uploadAvatar(
@Part("file") RequestBody file, // 文件
@Part("info") RequestBody userInfo // Json参数
);
// 调用示例:将UserRequest对象转为RequestBody
UserRequest userRequest = new UserRequest("李四", 30);
RequestBody userInfo = RequestBody.create(
MediaType.parse("application/json"),
new Gson().toJson(userRequest)
);
// 文件RequestBody(示例)
File file = new File("path/to/avatar.jpg");
RequestBody fileBody = RequestBody.create(
MediaType.parse("image/jpeg"),
file
);
Call<UploadResponse> call = apiService.uploadAvatar(fileBody, userInfo);
关键点:
@Part需配合@Multipart使用,适合混合数据类型(文件+Json)。- 需手动将Java对象转为
RequestBody并指定MediaType,不如@Body简洁。
@QueryMap + 手动Json:动态键值对转Json(特殊场景)
适用场景:当参数键名不确定(动态参数)或需要将Map转为Json时(如查询条件灵活的接口)。
实现方式:
- 使用
@QueryMap传递Map参数,Retrofit会将Map转为key1=value1&key2=value2格式。 - 若需Json格式,需手动将Map转为Json字符串,并通过
@Query或@Field传递。
示例:
// 方式1:手动构造Json字符串作为Query参数
@GET("/api/search")
Call<SearchResponse> search(@Query("filter") String filterJson);
// 调用示例
Map<String, Object> filter = new HashMap<>();
filter.put("minPrice", 100);
filter.put("maxPrice", 500);
filter.put("category", "electronics");
String filterJson = new Gson().toJson(filter);
Call<SearchResponse> call = apiService.search(filterJson);
// 方式2:使用@QueryMap(非Json,仅键值对)
@GET("/api/search")
Call<SearchResponse> search(@QueryMap Map<String, String> params);
局限性:
@QueryMap本身不生成Json,仅适合键值对参数,需额外手动处理Json转换。
如何选择?一张图区分Json传注方式
| 注解组合 | 适用场景 | 是否自动转Json | 参数类型 | 示例请求体格式 |
|---|---|---|---|---|
@Body |
复杂Json对象(嵌套、数组) | ✅(Converter自动转) | Java对象 | {"name":"张三","age":25} |
@Field+表编码 |
简单表单需Json字符串 | ❌(需手动构造Json) | String(Json字符串) | user_info={"name":"李四"} |
@Part+@Multipart |
文件+Json混合上传 | ✅(需手动转RequestBody) | RequestBody(Json部分) | multipart/form-data; boundary=xxx |
@QueryMap |
动态键值对(非Json) | Map | minPrice=100&category=电子 |
常见问题与注意事项
-
Converter配置缺失:
若未添加Gson/Moshi等Converter依赖,使用@Body时会抛出Unable to create @Body converter异常,确保Retrofit初始化时配置Converter:Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build(); -
@Body与@Field的混淆:@Body直接传递对象,适合application/json请求体;@Field需表单编码(@FormUrlEncoded),适合application/x-www-form-urlencoded。
-
Json格式与服务器要求一致:
检查服务器是否要求Content-Type: application/json,若需其他格式(如application/vnd.api+json),需通过@Headers或RequestBody手动指定。
在Retrofit中传参为Json,核心是根据参数类型和服务器要求选择注解:
- 复杂对象:优先用
@Body,自动序列



还没有评论,来说两句吧...