请求参数注解(四)
前言
在上一篇文章 请求参数注解(三) 中我们学习了 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~