【问题标题】:Retrofit2 - How to upload image using retrofit in multipart?Retrofit2 - 如何在多部分中使用改造上传图像?
【发布时间】:2017-01-14 19:46:40
【问题描述】:

我正在尝试使用retrofit2 beta 3 在服务器上上传图片。在响应中我得到了成功,但图片没有上传到服务器上。我不知道我在哪里犯错。 和

标题类型为 Content-Type: application/x-www-form-urlencoded

我的界面

@Multipart
@POST("/uploadFile")
Call<ResponseBody> upload(@PartMap Map<String, RequestBody> params);

我上传的方法是

上传图片和数据的方法

 private void uploadFile() {

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(Constants.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
   ApiInterface service =
            retrofit.create(ApiInterface.class);

    File file = new File(fileUri.getPath());
    Log.e(TAG, "uploadFile: " + file.toString());
    String fileName = "uploadFile\"; filename=\"" + file.getName();
    final RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
    final RequestBody empsno = RequestBody.create(MediaType.parse("text/plain"), strEmpsno);
    final RequestBody storsno = RequestBody.create(MediaType.parse("text/plain"), strStoreSno);
    final RequestBody strlr = RequestBody.create(MediaType.parse("text/plain"), strLrno);
    final RequestBody strtecq = RequestBody.create(MediaType.parse("text/plain"), strRecqty);
    final RequestBody strtecv = RequestBody.create(MediaType.parse("text/plain"), strRecvol);
    final RequestBody strtecw = RequestBody.create(MediaType.parse("text/plain"), strRecwgt);
    final RequestBody strdmg = RequestBody.create(MediaType.parse("text/plain"), strDamageqty);
    final RequestBody strlus = RequestBody.create(MediaType.parse("text/plain"), strLooseqty);
    final RequestBody strdd = RequestBody.create(MediaType.parse("text/plain"), strDeliverydate);
    final RequestBody strdt = RequestBody.create(MediaType.parse("text/plain"), strDeliverytime);
    final RequestBody strrem = RequestBody.create(MediaType.parse("text/plain"), strRemarks);
    final RequestBody strrec = RequestBody.create(MediaType.parse("text/plain"), strReceivedby);
    final RequestBody strip = RequestBody.create(MediaType.parse("text/plain"), strIpaddress);

    Map<String, RequestBody> oJSONObject = new HashMap<>();

    oJSONObject.put("empsno", empsno);
    oJSONObject.put("storesno", storsno);
    oJSONObject.put("lrSno", strlr);
    oJSONObject.put("recQty", strtecq);
    oJSONObject.put("recVol", strtecv);
    oJSONObject.put("recWgt", strtecw);
    oJSONObject.put("damageQty", strdmg);
    oJSONObject.put("looseQty", strlus);
    oJSONObject.put("deliveryDate", strdd);
    oJSONObject.put("deliveryTime", strdt);
    oJSONObject.put("remarks", strrem);
    oJSONObject.put("receivedBy", strrec);
    oJSONObject.put("ipAddress", strip);

    Call<ResponseBody> call = service.upload(oJSONObject);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            Log.e(TAG, "onResponse: " + response.isSuccessful());
            if (response.isSuccessful()) {
                Log.e(TAG, "onResponse: " + response.body());
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            Log.e(TAG, "onFailure: " + t.getLocalizedMessage());
        }
    });

}

响应 response.isSuccessful()=true。我的回复成功了,那么我的问题在哪里。请帮助我找到解决方案。

我也尝试过其他方式但没有成功,其他方式也有同样的结果

@Multipart
@POST("/uploadFile")
Call<Response> getDetails(@Part("empsno") RequestBody empsno,
                                @Part("storesno")RequestBody  storesno,
                                @Part("lrSno")RequestBody  lrSno,
                                @Part("recQty")RequestBody  recQty,
                                @Part("recVol")RequestBody  recVol,
                                @Part("recWgt")RequestBody  recWgt,
                                @Part("damageQty")RequestBody  damageQty,
                                @Part("looseQty")RequestBody  looseQty,
                                @Part("deliveryDate")RequestBody  deliveryDate,
                                @Part("deliveryTime")RequestBody  deliveryTime,
                                @Part("uploadFile\"; filename=\"abc.jpg\" ") RequestBody part,
                                @Part("remarks")RequestBody  remarks,
                                @Part("receivedBy")RequestBody  receivedBy,
                                @Part("ipAddress") RequestBody ipAddress

我在这里使用的方法是

File file = new File(fileUri.getPath());
        RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        MultipartBody.Part body = MultipartBody.Part.createFormData("uploadFile", file.getName(), requestFile);
        RequestBody empsno = RequestBody.create(MediaType.parse("text/plain"), strEmpsno);
        RequestBody storsno = RequestBody.create(MediaType.parse("text/plain"), strStoreSno);
        RequestBody strlr = RequestBody.create(MediaType.parse("text/plain"), strLrno);
        RequestBody strtecq = RequestBody.create(MediaType.parse("text/plain"), strRecqty);
        RequestBody strtecv = RequestBody.create(MediaType.parse("text/plain"), strRecvol);
        RequestBody strtecw = RequestBody.create(MediaType.parse("text/plain"), strRecwgt);
        RequestBody strdmg = RequestBody.create(MediaType.parse("text/plain"), strDamageqty);
        RequestBody strlus = RequestBody.create(MediaType.parse("text/plain"), strLooseqty);
        RequestBody strdd = RequestBody.create(MediaType.parse("text/plain"), strDeliverydate);
        RequestBody strdt = RequestBody.create(MediaType.parse("text/plain"), strDeliverytime);
        RequestBody strrem = RequestBody.create(MediaType.parse("text/plain"), strRemarks);
        RequestBody strrec = RequestBody.create(MediaType.parse("text/plain"), strReceivedby);
        RequestBody strip = RequestBody.create(MediaType.parse("text/plain"), strIpaddress);


        ApixInterface xInterface = retrofit.create(AudexInterface.class);
        Call<Response> podResponsecall = xInterface.getDetails(empsno, storsno, strlr, strtecq,
                strtecv, strtecw, strdmg, strlus, strdd, strdt,
                requestFile, strrem, strrec, strip);


        podResponsecall.enqueue(new Callback<Response>() {
            @Override
            public void onResponse(Call<Response> call, Response<Response> response) {
                Log.e(TAG, "onResponse: " + response.isSuccessful());
                if (response.isSuccessful()) {
                    Toast.makeText(getApplicationContext(), "Successfully saved!!!", Toast.LENGTH_LONG);
                    Log.e(TAG, "onResponse: " + response.body().getResult());
                    uploadFile();
                }
            }

            @Override
            public void onFailure(Call<Response> call, Throwable t) {
                Log.e(TAG, "onFailure: " + t.getLocalizedMessage());
            }
        });

通过使用此方法,响应也成功,但图像未上传到服务器。

提前致谢

【问题讨论】:

    标签: android retrofit multipartform-data retrofit2


    【解决方案1】:

    我的解决办法是:

    第一步。

    @Multipart
    @POST("Work/SendPic.ashx")
    Observable<ImgBean> uploadImg(@Part MultipartBody.Part file);
    

    第二步。

      RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"),file);
                        MultipartBody.Part body =
                                MultipartBody.Part.createFormData("img", file.getName(), requestBody);
    
                        UploadImg uploadImg = BaseRetrofit.getInstance().create(UploadImg.class);
    

    然后,它开始工作了。

    【讨论】:

    • 其他的细节呢,和图片一样吗?
    【解决方案2】:

    我观察到的是 Okhttp 中存在一些不上传图像的错误。像这样处理它:

    @Multipart
    @POST("api/chats/upload_chat_image")
    Call<UploadChatItemResponse> getImageLink(
            @Header("Authorization") String token,
            @Part("productid") RequestBody productid,
            @Part("touserid") RequestBody touserid,
            @Part("image\";filename=\"image.*\" ") RequestBody image);
    

    注意最后一部分。您可以为剩余项目创建@PartMap。但不要为文件这样做。此外,最后一部分的第一张图片应该是密钥服务器所期望的,而最后一张图片应该是原样。

    RequestBody uploadImage = RequestBody.create(MediaType.parse("image/png"), compressed_image);
        RequestBody productId = RequestBody.create(MediaType.parse("text/plain"), product.getProductid() + "");
        RequestBody userId = RequestBody.create(MediaType.parse("text/plain"), otherUserInfo.getUserid() + "");
        Call<UploadChatItemResponse> uploadChatImage = RestClient.getInstance(getApplicationContext()).getRestService()
                .getImageLink(PrefUtils.getToken(ChatActivity.this), productId, userId, uploadImage);
        uploadChatImage.enqueue(new Callback<UploadChatItemResponse>() {
            @Override
            public void onResponse(Call<UploadChatItemResponse> call, Response<UploadChatItemResponse> response) {
                if (response.body() != null && response.body().imageLink != null) {
                    sendMessage(response.body().imageLink, new ChatItem.ChatType(false, ChatItem.ChatType.CHAT_TYPE_IMAGE, ChatItem.ChatType.CHAT_SUBTYPE_NO_SUBTYPE));
                    sweetAlertDialog.dismiss();
                    compressed_image.delete();
                } else {
                    Toast.makeText(ChatActivity.this, "An error has occurred", Toast.LENGTH_SHORT).show();
                    sweetAlertDialog.dismiss();
                    compressed_image.delete();
                }
            }
    
            @Override
            public void onFailure(Call<UploadChatItemResponse> call, Throwable t) {
                Toast.makeText(ChatActivity.this, "An error has occurred", Toast.LENGTH_SHORT).show();
                sweetAlertDialog.dismiss();
                compressed_image.delete();
            }
        });
    

    注意我在为图像创建 RequestBody 时使用的类型。

    编辑:

    这是RestClient.java

    public class RestClient extends ContextWrapper {
    
    private static final String BASE_URL = "https://www.restapi.in";
    private APIService apiService;
    private static RestClient restClient;
    private static OkHttpClient okHttpClient;
    private static final int READ_TIMEOUT = 100 * 1000;
    private static final int CONNECTION_TIMEOUT = 100 * 1000;
    private static final int CACHE_SIZE = 4;
    private static final String CERTIFICATE_DOMAIN = "www.restclient.in";
    private static final String[] CERTIFICATE_SHA = {"sha256/dkjabkjabcbakjbakjsbcabcahkcbakcbakcbakh=",
                                                     "sha256/ckjdcndkjcnjcnajcnajskcnakjcnakjcnaksjcna=",
                                                     "sha256/cjkacakjcbajcbasjkcbacjcbakcbcbakjbcjkacb="};
    
    private RestClient(Context context) {
        super(context);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(getOkHttpClient(context))
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        apiService = retrofit.create(APIService.class);
    }
    
    public static RestClient getInstance(Context context){
        if(restClient==null)
            restClient = new RestClient(context.getApplicationContext());
        return restClient;
    }
    
    private static OkHttpClient getOkHttpClient(Context context){
        if (okHttpClient == null) {
            HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
            logger.setLevel(BuildConfig.DEBUG?HttpLoggingInterceptor.Level.HEADERS:HttpLoggingInterceptor.Level.NONE);
            CertificatePinner.Builder certificatePinnerBuilder = new CertificatePinner.Builder();
            for(String sha : CERTIFICATE_SHA)
                certificatePinnerBuilder.add(CERTIFICATE_DOMAIN, sha);
            okHttpClient = new OkHttpClient.Builder()
                    .cache(setCache(context))
                    .certificatePinner(certificatePinnerBuilder.build())
                    .retryOnConnectionFailure(false)
                    .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
                    .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
                    .addInterceptor(new Interceptor() {
                        @Override
                        public okhttp3.Response intercept(Chain chain) throws IOException {
                            Request original = chain.request();
    
                            Request request = original.newBuilder()
                                    .header("Content-type", "application/json")
                                    .header("Accept", "application/json")
                                    .method(original.method(), original.body())
                                    .build();
    
                            return chain.proceed(request);
                        }
                    })
                    .addInterceptor(logger)
                    .build();
        }
        return okHttpClient;
    }
    
    private static Cache setCache(Context context) {
        int cacheSize = CACHE_SIZE * 1024 * 1024;
        return new Cache(new File(context.getCacheDir(), "http"), cacheSize);
    }
    
    public APIService getRestService(){
        return apiService;
    }
    

    }

    【讨论】:

    • 在我的情况下,授权作为“授权标头”传递,从第一个代码 sn-p 可以看出,但您可以根据需要调整 RestClient.java。
    • @Embydextrous 我们可以同时使用注释(@Part 和@Header)吗?我得到了 java.lang.IllegalArgumentException: Only one encoding annotation is allowed.
    • 您是否同时使用@Multipart@FormUrlEncoded 注释。
    • @Embydextrous 对不起,我的错误。谢谢你的澄清
    【解决方案3】:

    只需删除标题类型

    @headers({Content-Type: application/x-www-form-urlencoded})
    

    【讨论】:

      猜你喜欢
      • 2018-04-15
      • 2021-11-17
      • 2016-04-10
      • 2017-11-02
      • 2015-09-16
      • 2019-12-19
      • 2016-10-13
      • 1970-01-01
      • 2015-05-02
      相关资源
      最近更新 更多