请求参数注解(四)
前言
在上一篇文章 请求参数注解(三) 中我们学习了 Field 注解,本篇文章我们学习了 Part 相关的注解。

从上图可以看出与 Part 相关的注解有:
@Part@PartMap
multipart/form-data
在 Retrofit 中与 @Part 注解相关的是 @Multipart 注解,在 HTTP 中与 @Multipart 注解相关的是 multipart/form-data 编码方式,所以我们先简单学习下 multipart/form-data 相关的知识,来更好的理解 @Part 注解的作用。
multipart/form-data 是表单提交中的一种编码方式,它的定义可以参考 RFC-7578 4.1章节,简单理解:multipart/form-data 可以包含一个或多个 Part,每个 Part 之间由 boundary 参数分隔。
以下是一个简单的 multipart/form-data 请求示例:
POST /user/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=123456
--123456
Content-Disposition: form-data; name="username"
guodongAndroid
--123456
Content-Disposition: form-data; name="file"; filename="水墨西湖.jpg";
<水墨西湖.jpg>
--123456--
- 第2行:
Content-Type请求头的值是我们设置的multipart/form-data编码方式,它有一个必选参数boundary,用于分隔每个Part, - 第3行:空白行,
- 第4行:
Part的分隔符,格式为:--<boundary>, - 第5行:
Part部分的必选头字段:Content-Disposition,其值必须为:form-data,必须包含一个name的参数, - 第6行:
Part部分的内容(body) - 第7行:
Part的分隔符,格式为:--<boundary>, - 第8行:
Part部分的必选头字段:Content-Disposition,其值必须为:form-data,必须包含一个name的参数,如果是文件,还可以包含一个filename参数, - 第9行:文件的二进制数据,此处以文字代替,
- 第10行:最后一个
Part结尾符,格式为:--<boundary>--,
通过上述示例,对于 Part 我们可以简单理解:就是我们需要传入的数据。
有关
Part的详细信息可以参考 RFC-2046 5.1章节。
@Part
@Part 注解标记HTTP接口方法中的一个参数,表示这个参数是 Form 表单里的一个 Part。
@Part 注解有两个参数,分别为:
value:可选参数,表示Part中name参数的值,encoding:可选参数,表示Part中的可选头字段Content-Transfer-Encoding的值,Retrofit 默认:binary,HTTP协议默认:7-bit,
简单使用示例:
interface Service {
@Multipart
@POST("foo/bar")
Call<ResponseBody> method(@Part("lang") String lang);
}
Service service = retrofit.create(Service.class);
service.method("zh");
@Part 注解使用时有以下几点需要注意:
@Part注解仅能在被@Multipart注解标注的方法中使用,否则抛出异常,如果注解标记的参数类型是
okhttp3.MultipartBody.Part,value参数的值取自okhttp3.MultipartBody.Part中,value参数不可填充值,否则抛出异常,- 可以标记
okhttp3.MultipartBody.Part的集合和数组类型,
- 可以标记
如果注解标记的参数类型是其他类型,
value参数必须填充值,否则抛出异常,- 其他类型的参数值会经过
Retrofit#requestBodyConverter(Type, Annotation[], Annotation[])转换,
- 其他类型的参数值会经过
如果参数值为
null,则会被忽略,
| 标记参数类型 | value 是否填充 | encoding 是否有效 |
|---|---|---|
okhttp3.MultipartBody.Part | 必须为空 | 无效 |
| 其他类型 | 必须填充 | 有效 |
@PartMap
@PartMap 注解标记HTTP接口方法中的一个参数,表示这个参数是 Form 表单里的一个或多个 Part。
@PartMap 注解目前只有一个参数:
encoding:可选参数,表示Part中的可选头字段Content-Transfer-Encoding的值,Retrofit 默认:binary,HTTP协议默认:7-bit,
简单使用示例:
interface Service {
@Multipart
@POST("foo/bar")
Call<ResponseBody> method(@Part("lang") String lang, @PartMap Map<String, String> parts);
}
Service service = retrofit.create(Service.class);
service.method("zh", ImmutableMap.of("foo", "bar", "kit", "kat");
@PartMap 注解使用时有以下几点需要注意:
@PartMap注解仅能在被@Multipart注解标注的方法中使用,否则抛出异常,- 被标注的参数类型必须是
Map,否则抛出异常, Map中键的类型必须是String类型,否则抛出异常,如果键的值为null,则抛出异常,Map中值的类型不能是okhttp3.MultipartBody.Part,否则抛出异常,Map中值如果值为null,则抛出异常,Map中值会经过Retrofit#requestBodyConverter(Type, Annotation[], Annotation[])转换,如果转换后的值为null,则抛出异常,
总结
@Part 和 @PartMap 注解与 @Field 和 @FieldMap 注解在类型和适用场景方面非常类似:
| 注解 | 类型 | 适用场景 |
|---|---|---|
@Part | 动态 | 明确 name 参数值,不明确 Part 内容 |
@PartMap | 动态 | 1.name 参数值和 Part 内容都不明确2.一次传入多个 Part |
但是,在功能支持方面,@Part 和 @PartMap 注解相对于 @Field 和 @FieldMap 注解要强大一些:前者支持文件上传,由于文件上传较为复杂,操作步骤较多,那么前者的易用性自然就有所降低。
总之,@Part 和 @PartMap 注解在使用时还是需要多多注意的。
希望可以帮你更好的使用 Retrofit,happy~
