You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 00:20:56