使用Retrofit通过multipart/form-data上传图片失败求助
我看到你遇到了用Retrofit发送multipart图片时的连接超时问题,而且Postman测试完全正常,这确实挺让人挠头的。咱们从错误信息和代码细节入手,一步步排查解决:
先拆解错误信息
你给出的错误:
failed to connect to .30::681c:587 (port 443) from /fec0::9c04. (port 38630) after 10000ms
核心问题是网络连接超时,而且目标IP地址格式异常(.30::开头明显不对),大概率是域名解析或者请求URL拼接出了问题。
针对性排查方案
1. 优先检查Retrofit的BaseUrl配置
你接口里的@POST("requests/11006/history")是相对路径,那你创建Retrofit实例时的BaseUrl必须正确:
- 确保BaseUrl以
/结尾,比如如果Postman用的完整URL是https://your-api-domain.com/requests/11006/history,那BaseUrl应该是https://your-api-domain.com/ - 可以通过OkHttp的日志拦截器打印拼接后的完整请求URL,确认和Postman里的URL完全一致,避免路径拼接错误导致解析出异常IP
2. 调整Retrofit的超时时间
默认的OkHttpClient超时时间是10秒,你的错误刚好是10秒后超时,大概率是图片上传需要更长时间。可以在创建OkHttpClient时延长超时:
val okHttpClient = OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) // 上传大文件重点调整这个参数 .build() // 把配置好的client传给Retrofit val retrofit = Retrofit.Builder() .baseUrl(YOUR_BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build()
3. 确认RequestBody的MediaType有效性
你用contentResolver.getType(fileUri)获取MediaType,某些情况下可能返回null或错误类型,试试直接指定图片的MediaType:
// 比如图片是jpeg格式,直接明确指定 val filePart = RequestBody.create(MediaType.parse("image/jpeg"), originalFile) // 如果是新版本Retrofit,用这个写法更稳妥: // val filePart = RequestBody.create(MediaType.Companion.parse("image/jpeg"), originalFile)
4. 核对表单字段名
你用MultipartBody.Part.createFormData("image[]", ...),确认Postman里的form-data字段名也是image[](如果Postman里是image,那这里就错了,虽然这一般会导致服务器返回参数错误,但还是可以排除下这个可能性)
5. 检查网络相关配置(Android端)
- 确认Manifest里加了网络权限:
<uses-permission android:name="android.permission.INTERNET" /> - 如果是Android 9+,服务器用的是HTTP而非HTTPS,需要在
res/xml/network_security_config.xml里配置允许明文请求,或者改用HTTPS(Postman能正常访问的话这个概率低,但还是确认下)
6. 排查DNS解析问题
错误里的异常IP可能是域名解析失败导致的,试试直接把BaseUrl换成服务器的真实IP地址,看能不能正常连接。如果可以,那就是DNS解析的问题,需要检查设备的DNS设置。
总结
先从BaseUrl拼接和超时时间调整入手,这两个是最常见的触发此类问题的原因。如果还没解决,再一步步排查MediaType、字段名、网络配置这些点。
内容的提问来源于stack exchange,提问作者Айдар Сабирзянов

