Android中Retrofit Multipart Entity上传图片失败(Postman可正常上传)求助
我来帮你排查下这个头疼的问题——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

