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

Android中Retrofit Multipart Entity上传图片失败(Postman可正常上传)求助

解决Retrofit Multipart上传图片提示“文件未找到”的问题

我来帮你排查下这个头疼的问题——Postman能正常上传但Retrofit不行,大概率是请求构造的细节和Postman不一致导致的,咱们一步步来定位:

1. 先检查文件路径与文件存在性

你传入的是ArrayList<String> filePaths,首先要确认这些路径是绝对路径,并且对应的文件确实存在。很多时候失败都是因为文件路径不对,或者App没有读取文件的权限。

建议在添加文件前做个存在性检查,并且把路径转成File对象再上传:

for (String path : filePaths) {
    File uploadFile = new File(path);
    if (!uploadFile.exists()) {
        Log.e("UploadError", "文件不存在:" + path);
        continue; // 跳过不存在的文件,避免影响整个请求
    }
    // 这里要注意参数名!要和Postman里的文件参数名完全一致,比如Postman里是"files"就写"files",是"file[]"就写"file[]"
    builder.addFormDataPart(
        "files", // 替换成你Postman里的文件参数名
        uploadFile.getName(),
        RequestBody.create(MediaType.parse("image/*"), uploadFile)
    );
}

2. 核对MediaType与服务器要求

Postman会自动识别文件的MIME类型,但Retrofit需要你明确指定。如果服务器严格要求特定类型(比如image/jpeg、image/png),不要用泛型的image/*,要对应文件的实际类型:

// 比如判断文件后缀来设置正确的MediaType
String mimeType = getMimeType(uploadFile.getAbsolutePath());
RequestBody fileBody = RequestBody.create(MediaType.parse(mimeType), uploadFile);

// 辅助方法:根据后缀获取MIME类型
private String getMimeType(String path) {
    String extension = MimeTypeMap.getFileExtensionFromUrl(path);
    return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}

3. 确保表单字段名完全匹配服务器要求

服务器的参数名是大小写敏感的!比如你代码里的"userid",要和Postman里的参数名完全一致——如果Postman里是"userId",那这里就必须改成"userId",差一个大小写都会导致参数不识别,甚至影响文件上传逻辑。

4. 检查Retrofit接口的注解是否正确

如果你的接口定义有问题,也会导致请求构造失败。比如正确的Multipart接口应该是这样的:

// 方式1:用@PartMap传递普通字段,@Part传递文件列表
@Multipart
@POST("your-api-url/visitrecord")
Call<YourResponseModel> uploadVisitRecord(
    @PartMap Map<String, RequestBody> formFields,
    @Part List<MultipartBody.Part> files
);

// 方式2:直接传递构建好的MultipartBody
@POST("your-api-url/visitrecord")
Call<YourResponseModel> uploadVisitRecord(@Body MultipartBody body);

如果是用方式1,你需要把普通字段(userid、companyId等)也转成RequestBody:

Map<String, RequestBody> formMap = new HashMap<>();
formMap.put("userid", RequestBody.create(MediaType.parse("text/plain"), userId));
formMap.put("companyId", RequestBody.create(MediaType.parse("text/plain"), companyId));
// 其他字段同理

5. 确认Android权限是否到位

Android 6.0及以上版本,读取外部存储需要动态申请权限。如果你的App没有READ_EXTERNAL_STORAGE权限,根本读不到文件,自然上传失败。

记得在Manifest里添加权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

并且在代码里动态申请权限,拿到授权后再执行上传操作。

6. 对比Postman和Retrofit的请求日志

最直接的方法是把Retrofit的请求日志打出来,和Postman的请求做对比,看哪里不一样。添加日志拦截器:

// 添加HttpLoggingInterceptor依赖后
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addInterceptor(loggingInterceptor)
    .build();

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(BASE_URL)
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build();

然后看Logcat里的请求体,对比Postman的Raw请求,重点看:

  • 表单字段的名称和值是否正确
  • 文件是否被正确添加(有没有Content-Disposition和文件内容)
  • 请求头的Content-Type是否为multipart/form-data; boundary=xxx

按上面的步骤排查,应该能找到问题所在啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:28:30