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

Retrofit Multipart上传图片使用image/*返回400错误原因及解决方案

问题产生原因
  • HTTP规范中,image/*这类带通配符*的MIME写法,仅允许出现在Accept请求头中,用于告知服务端客户端可接收的响应类型范围,不能作为实体内容的Content-Type值使用。
  • Retrofit底层依赖OkHttp构造Multipart请求时,不会主动解析替换通配符MIME,会直接把你传入的image/*写到图片分片的Content-Type头中透传给后端。绝大多数后端的文件上传校验逻辑(包括常用的Spring、Express文件上传中间件)只会做精确MIME匹配,不会识别通配符,收到非法的Content-Type值会直接判定请求参数不合法,返回400 Bad Request。
  • 手动指定image/jpg这类明确MIME后,分片头的Content-Type符合后端校验规则,自然就能上传成功。
支持任意图片格式上传的正确实现

不要硬编码固定MIME,也不要使用通配符,应该在构造请求前自动探测图片文件的真实MIME类型,Android端可以直接用系统自带的MimeTypeMap实现,无需引入额外依赖:

  1. 编写MIME探测工具方法,兜底处理无法识别类型的场景:
import android.webkit.MimeTypeMap
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File

private fun fetchFileMimeType(file: File): String {
    val fileExtension = MimeTypeMap.getFileExtensionFromUrl(file.name)
        ?: return "application/octet-stream"
    return MimeTypeMap.getSingleton()
        .getMimeTypeFromExtension(fileExtension.lowercase())
        ?: "application/octet-stream"
}
  1. 构造图片上传分片时,使用探测到的真实MIME,可提前增加类型校验拦截非图片文件:
// 获取文件真实MIME
val mimeType = fetchFileMimeType(imageFile)
// 校验是否为图片类型
check(mimeType.startsWith("image/")) { "所选文件不是合法图片格式" }
// 构造请求体
val imageBody = imageFile.asRequestBody(mimeType.toMediaTypeOrNull())
val imagePart = MultipartBody.Part.createFormData("image", imageFile.name, imageBody)

补充说明:如果需要做更严格的安全校验,避免用户通过修改文件后缀上传恶意文件,可以在MIME探测逻辑中增加文件头魔数校验,读取文件前几个字节判断真实文件类型,校验通过后再构造上传请求。

内容的提问来源于stack exchange,提问作者Zen Ryuu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:39:20