pendingitentandnroid

Retrofit上传图片

2017-04-27  本文已影响4632人  sankemao

关于使用retrofit上传图片, 网上有许多教程, 再次做一下粗略的总结.
上传图片为post请求, 先写接口, 一般来说有下面四种写法:

@Multipart
@POST("user/imgUpLoad")
//1
//Call<String> uploadOne(@Part("sign") String sign,@Part("appKey") String appKey,@Part("osName") String osName,@Part("memberNo") String memberNo, @Part  MultipartBody.Part file);
//2
//Call<String> uploadOne(@PartMap Map<String,String> params, @Part  MultipartBody.Part file);
//3
//Call<String> uploadOne(@Query("sign") String sign, @Query("appKey") String appKey, @Query("osName") String osName, @Query("memberNo") String memberNo, @Part  MultipartBody.Part file);
//4
Call<String> uploadOne(@QueryMap Map<String,String> params, @Part  MultipartBody.Part file);

1和2这种写法本质是一样的, @Part后面的参数, 都是放在请求体中.
3和4则是另一种方式的同一写法, @Query后面的参数回拼接在url后面.

在上传图片之前, 我先在postman中请求了一下, 测试一下参数是否都正确

postman
按照后台提供的接口和参数, 一切正常.
ok, 下面继续回到代码中
@Multipart
@POST("pronline/upload")
Call<ResponseBody> upImg(@PartMap Map<String,String> params,@Part MultipartBody.Part file);
String fileNameByTimeStamp = FormatUtil.getTimeStamp() + ".jpg";
File file = new File(imgPath);
RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpeg"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("app_user_header", fileNameByTimeStamp, requestFile);
Map<String, String> params = new HashMap<>();
params.put("FunName", "ict_uploadpicture");
params.put("path", "/uploadNews");
params.put("appfile", fileNameByTimeStamp);
HttpUtils.getInstance().getAPI()
                        .upImg(params, body)
                        .enqueue(new Callback<ResponseBody>() {
                            ...
                        }

一般来说到这里上传图片解成功了.
然并卵, 服务器无情的给我返回了 500 Internal Server Error,表示服务器内部错误,证明我们传过去的东东,后台处理的时候发生异常。(这里吐槽下后台的哥们没有catch处理下异常给个提示)
明明在postman中可以正常上传的...
于是我用Wireshark对postman和retrofit上传图片进行抓包

Wireshark过滤ip规则:ip.dst==192.168.1.1

结果如下:

postman抓包结果 retrofit
盲僧, 我发现了华点, 看到了没有, 红框部分, retrofit请求的content-type
application/json, 而postman的请求则没有content-type
参考:http://blog.csdn.net/zjm0518/article/details/60781238

既然发现问题就好办了, 直接把content-type给去掉呗.

    @Multipart
    @POST("pronline/upload")
    Call<ResponseBody> upImg(@Part("FunName") RequestBody funName,
                             @Part("path") RequestBody path,
                             @Part("appfile") RequestBody appfile,
                             @Part MultipartBody.Part file);
//funName
RequestBody funName = RequestBody.create(null, "ict_uploadpicture");
//path
RequestBody path = RequestBody.create(null, "/uploadNews");
//appfile
RequestBody appfile = RequestBody.create(null, fileNameByTimeStamp);
//上传图片的名字
String fileName = FormatUtil.getTimeStamp() + ".jpg";
//图片文件
File file = new File(imgPath);
RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpeg"), file);
/**
  *file部分,最终拼接成以下部分(注意“app_user_header”是后台定义好的,后台会用它作为key去查询你传的图片信息):
  *Content-Disposition: form-data; name="app_user_header"; filename=fileNameByTimeStamp
  *Content-Type: image/jpeg
  *Content-Length: 52251(图片流字节数组的长度,底层的Okhttp帮我们计算了)
  *...(文件流)
  */
MultipartBody.Part body = MultipartBody.Part.createFormData("app_user_header", fileName, requestFile);

关键是这句RequestBody.create(null, "ict_uploadpicture");第一个参数传入MediaType,
直接传null, 表示content-type为空.

-- END

上一篇 下一篇

猜你喜欢

热点阅读