Retrofit Multipart请求中@Part传Null报400,如何保留参数不传文件?
解决Retrofit上传Multipart时保留可选参数项(无文件)的问题
问题核心:当你给Retrofit的@Part参数传null时,Retrofit会自动忽略这个参数,不会把它加入到Multipart请求里。而你的后端期望这些参数项必须存在(哪怕没有文件内容),所以才返回400错误。
下面提供两种可行的解决方法:
方法1:使用@PartMap显式控制所有参数
把多个独立的@Part参数替换成@PartMap,这样可以手动为每个参数项赋值,即使没有文件也能保留参数名。
第一步:修改接口定义
@POST("transactions/recordTransaction") fun uploadTransaction( @Header("Authorization") token: String, @PartMap partMap: Map<String, RequestBody>, @Part("transactionRecord") transactionRecord: RequestBody ): Deferred<TithePaymentResponse>
第二步:构建参数Map并发起请求
// 创建空RequestBody,用于占位无文件的参数 val emptyFileBody = RequestBody.create(MediaType.parse("application/octet-stream"), "") // 构建参数Map,确保每个文件参数项都存在 val partMap = mutableMapOf<String, RequestBody>().apply { // 注意这里的key格式要符合Multipart文件参数的规范:"参数名\"; filename=\"" this["brideIdFront\"; filename=\""] = brideIdFront?.body ?: emptyFileBody this["brideIdBack\"; filename=\""] = brideIdBack?.body ?: emptyFileBody this["groomIdFront\"; filename=\""] = groomIdFront?.body ?: emptyFileBody this["groomIdBack\"; filename=\""] = groomIdBack?.body ?: emptyFileBody this["chequePhoto\"; filename=\""] = chequePhoto?.body ?: emptyFileBody } val uploadTithe = ApiService.DeliveranceApi.retrofitService.uploadTransaction( token = "Bearer ${Constants.Token}", partMap = partMap, transactionRecord = transactionRecordBody )
方法2:手动构建MultipartBody
直接自己组装整个Multipart请求体,完全控制每个参数项的存在与否。
第一步:修改接口定义
@POST("transactions/recordTransaction") fun uploadTransaction( @Header("Authorization") token: String, @Body multipartBody: MultipartBody ): Deferred<TithePaymentResponse>
第二步:构建MultipartBody并发起请求
val multipartBody = MultipartBody.Builder() .setType(MultipartBody.FORM) // 添加必填的请求体 .addFormDataPart("transactionRecord", null, transactionRecordBody) // 逐个处理文件参数:有文件就加文件Part,没有就加空内容的参数项 .apply { brideIdFront?.let { addPart(it) } ?: addFormDataPart("brideIdFront", "", "") brideIdBack?.let { addPart(it) } ?: addFormDataPart("brideIdBack", "", "") groomIdFront?.let { addPart(it) } ?: addFormDataPart("groomIdFront", "", "") groomIdBack?.let { addPart(it) } ?: addFormDataPart("groomIdBack", "", "") chequePhoto?.let { addPart(it) } ?: addFormDataPart("chequePhoto", "", "") } .build() val uploadTithe = ApiService.DeliveranceApi.retrofitService.uploadTransaction( token = "Bearer ${Constants.Token}", multipartBody = multipartBody )
两种方法的核心都是确保每个要求的参数项都出现在Multipart请求中,没有文件时就传空内容,这样后端就能识别到参数存在,不会返回400错误。
内容的提问来源于stack exchange,提问作者Dennis
相关产品推荐
相关产品推荐

