9

Прочтите править в нижней части вопроса для возможного альтернативного решения, пока решение не будет найдено.Модернизация 2 не может загрузить файл с двумя дополнительными отдельными строковыми параметрами

Это успешный почтовый файл с двумя параметрами с использованием POSTMan. Я пытаюсь сделать то же самое с модификацией, но получаю BadRequest.

Почтальон Настройки:

enter image description here

Chrome сети Сообщение Детали: enter image description here

Теперь вот как я это делаю в Android, но не суметь:

Дооснащение Интерфейс службы:

@Multipart 
@POST("jobDocuments/upload") 
Call<ResponseBody> upload(@Part("file") MultipartBody.Part file,@Part("folder") MultipartBody.Part folder,@Part("name") MultipartBody.Part name); 

Это мой @Background метод для запуска сетевого запроса с вышеуказанной службой генерируется

CustDataClient service = 
      ServiceGenerator.createService(CustDataClient.class); 
    File file = new File(fileUri.getPath()); 
    // create RequestBody instance from file 
    RequestBody requestFile = 
      RequestBody.create(MediaType.parse("multipart/form-data"), file); 

    MultipartBody.Part fileData = 
      MultipartBody.Part.createFormData("file", fileName, requestFile); 
    MultipartBody.Part folder = 
      MultipartBody.Part.createFormData("folder", "LeadDocuments"); 
    MultipartBody.Part name = 
      MultipartBody.Part.createFormData("name", fileName); 
    // finally, execute the request 
    Call<ResponseBody> call = service.upload(fileData,folder,name); 
    try { 
     Response<ResponseBody> rr = call.execute(); 
     ResponseBody empJobDocsResult = rr.body();//Bad Request here :(
     Log.v("Upload", "success"); 
    } catch (Exception ex) { 
     Log.e("Upload error:", ex.getMessage()); 
    } 

Вот мой Web Api Метод:

[Route("upload")] 
    [HttpPost] 
    public IHttpActionResult Upload() 
    { 
     if (HttpContext.Current.Request.Files.AllKeys.Any()) 
     { 
      // Get the uploaded image from the Files collection 
      var httpPostedFile = HttpContext.Current.Request.Files["file"]; 

      if (httpPostedFile != null) 
      { 
       // Validate the uploaded image(optional) 
       var folder = HttpContext.Current.Request.Form["folder"]; 
       var fileName = HttpContext.Current.Request.Form["name"]; 
       fileName = string.IsNullOrEmpty(fileName) ? httpPostedFile.FileName : fileName; 
       // Get the complete file path 
       var fileSavePath = Path.Combine(HttpContext.Current.Server.MapPath("~/Files/" + folder), fileName); 

       // Save the uploaded file to "UploadedFiles" folder 
       httpPostedFile.SaveAs(fileSavePath); 

       return Ok(new OkMessage { Message = "File uploaded successfully", Path = "/Files/" + folder + "/" + fileName }); 
      } 
     } 

     return BadRequest("File not uploaded"); 
    } 

Пожалуйста, помогите, где я я ошибаюсь и как это сделать, есть ли простая альтернатива модернизации?

[Редактировать] Этот код успешно работает, благодаря koush/ion:

Ion.with(getContext()) 
          .load("POST", "http://www.dgheating.com/api/jobDocuments/upload") 
          .setMultipartParameter("folder", "LeadDocuments") 
          .setMultipartParameter("name", fileName) 
          .setMultipartFile("file", new File(imagePath)) 
          .asJsonObject() 
          .setCallback(...); 
+0

Я была такая же проблема с Android, и точнее, с 4.1.1; Теперь, используя пример с Ion, проблема решена, и теперь я могу без проблем загружать файлы (изображения в моем случае). Вы должны опубликовать редактирование Ion как ответ (я думаю). –

+0

Нет, это не решение проблемы, а альтернатива (избегая проблемы). – ahmadalibaloch

+0

это отстой. Вы когда-нибудь находили решение этого? –

ответ

0

Похоже, ваше определение сервиса является неправильным. Попробуйте

@Multipart 
@POST("jobDocuments/upload") 
Call<ResponseBody> upload(@Part("file") MultipartBody.Part file,@Part("folder") RequestBody folder,@Part("name") RequestBody name); 

и

RequestBody folder = 
     RequestBody.create(
       MediaType.parse("multipart/form-data"), "LeadDocuments"); 
RequestBody name = 
     RequestBody.create(
       MediaType.parse("multipart/form-data"), filename); 

в методе @Background. Все это предполагает, что вы используете Retrofit2.

+0

Отсутствие успеха с вышеуказанной коррекцией тоже. Да, его модификация2. :( – ahmadalibaloch

+1

не работает, это исключение вызывает: 'java.lang.IllegalArgumentException: параметры @Part с помощью MultipartBody.Part не должны включать имя детали в аннотацию.' – Hesam

+0

Hesam, вы используете вместо @Part вместо @Part («file»). – Bakus123

2

Использование Retrofit 2, вам необходимо использовать классы RequestBody или MultipartBody.Part OkHttp и инкапсулировать ваш файл в тело запроса. Давайте посмотрим на определение интерфейса для загрузки файлов. Вы видели https://futurestud.io/blog/retrofit-2-how-to-upload-files-to-server

+0

Да, все вышеприведенные вопросы в этом вопросе были фактически начаты в этом учебнике, а его почти идентичные, за исключением дополнительных двух строковых параметров. Плюс Ion-библиотека отлично работает с теми же данными и настройками. – ahmadalibaloch

1

Интерфейс для Модернизированный (API)

public interface API { 

    String NAME = "name"; 
    String FOLDER = "folder"; 
    @Multipart 
    @POST("/api/jobDocuments/upload") 
    Call<JsonResponse> uploadFile(
     @Part(NAME) String name, 
     @Part(FOLDER) String folder, 
     @Part MultipartBody.Part file); 
} 

Response Класс (JsonResponse)

public class JsonResponse { 

    @SerializedName("$id") 
    public String id; 
    @SerializedName("Message") 
    public String message; 
    @SerializedName("Path") 
    public String path; 

    public JsonResponse(String id, String message, String path) { 
     this.id = id; 
     this.message = message; 
     this.path = path; 
    } 
} 

API вызова из приложения

Retrofit retrofit; 

private void postImage() { 
    String URL = "http://www.dgheating.com/"; 

    //your file location 
    File file = new File(Environment.getExternalStorageDirectory() + "/Image.png"); 

    //parameters 
    String NAME = file.getName(); 
    String FOLDER = "LeadDocuments"; 
    String FILE = "file"; 

    retrofit = new Retrofit.Builder() 
      .baseUrl(URL) 
      .addConverterFactory(GsonConverterFactory.create(new Gson())) 
      .build(); 
    API api = retrofit.create(API.class); 
    RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); 
    MultipartBody.Part part = MultipartBody.Part.createFormData(FILE, NAME, requestBody); 
    Call<JsonResponse> call = api.uploadFile(NAME, FOLDER, part); 

    call.enqueue(new Callback<JsonResponse>() { 
     @Override 
     public void onResponse(Call<JsonResponse> call, Response<JsonResponse> response) { 
      //response.body()   null 
      //response.code()   500 

      //https://github.com/square/retrofit/issues/1321 
      Converter<ResponseBody, JsonResponse> errorConverter 
        = retrofit.responseBodyConverter(JsonResponse.class, new Annotation[0]); 
      try { 
       JsonResponse jsonResponse = errorConverter.convert(response.errorBody()); 
       Log.e("error", "id:" + jsonResponse.id);    //1 
       Log.e("error", "message:" + jsonResponse.message);  //An error has occurred 
       Log.e("error", "path:" + jsonResponse.path);    //null 
      } catch (IOException ignored) { 
      } 
     } 

     @Override 
     public void onFailure(Call<JsonResponse> call, Throwable t) { 

     } 
    }); 
} 

Ошибка в полях, из-за любого из этих вопроса сервера

  1. Google
  2. HTTP 500 response using retrofit, but Post request through Postman gives desired response
  3. How to get response body to retrofit exception?
  4. Retrofit SocketTimeoutException (and/or http 500 error) on http-POST
+0

Я скоро проверю и дайте обратную связь. – ahmadalibaloch

6

Итак, надеюсь, что это не слишком поздно, и если так - это mi GHT помочь кому-то еще :) мои 2 цента об это после того, как та же проблема некоторое время назад:

Определение службы, используя @Part только (изменить имена полей в соответствии с тем, что ожидает ваш сервер)

//Single image MultiPart 
@Multipart 
@POST("user/imageupload") 
Call<ResponseBody> upload(@Part("userfile") RequestBody file, @Part("userid") RequestBody description); 

И для магического трюка я отношусь к обеим частям так же, как RequestBody, используя MediaType.parse() для каждого из них с собственным типом, опираясь на определение @Multipart для самого запроса, нет необходимости в form-data материалах, то же самое работает для нескольких файлов и несколько полей:

private static final String IMG_JPEG = "image/jpeg"; 
private static final String TXT_PLAIN = "text/plain"; 

public void uploadImageMultipart(Uri uri, final CustomEventListener<String> listener) 
{ 
    RequestBody fileBody; 
    RequestBody textBody; 
    File file = new File(uri.getPath()); 
    Call<ResponseBody> requestCall; 

    fileBody = RequestBody.create(okhttp3.MediaType.parse(IMG_JPEG), file); 
    textBody = RequestBody.create(okhttp3.MediaType.parse(TXT_PLAIN), String.valueOf(SettingsManager.getUserID())); 

     requestCall = serviceCaller.upload(fileBody, textBody); 
     requestCall.enqueue(new Callback<ResponseBody>() 
     { 
     @Override 
     public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse) 
     { 
      try 
      { 
       String response = rawResponse.body().string(); 
       //from here it's your show.... 
       listener.getResult("Got it"); 
      } 
      catch (Exception e) 
      { 
         e.printStackTrace(); 
      } 
     } 

     @Override 
     public void onFailure(Call<ResponseBody> call, Throwable throwable) 
     { 

     } 
    }); 
} 

(Я использую прослушиватель, чтобы вернуть ответ обратного вызова в другую часть приложения (например, вызывающая деятельность)).

Это определенно отправляет файл/с и текстовое поле, другие проблемы, вероятно, будут происходить с серверной стороны.

Надеюсь, что это поможет!

+0

ваше решение работает лучше всего для меня. Я столкнулся с аналогичной проблемой здесь: http://stackoverflow.com/questions/43320205/android-with-retrofit2-okhttp3-multipart-post-error. Проблема была в части тела который является String, исправил его с помощью MediaType «text/plain», например: textBody = RequestBody.create (okhttp3.MediaType.parse (TXT_PLAIN), String.valueOf (SettingsManager.getUserID())); ' –

+0

@shuwnyuantee Рад, что я мог бы помочь, вы также можете обратиться к http://stackoverflow.com/questions/28172496/android-volley-how-to-isolate-requests-in-another-class/30604191#30604191 за чистый способ использования интерфейса CustomEventListener (общая идея похожа на Volley и Retrofit) – TommySM

+0

классный @TommySM, выйдет на Volley :) –

3

я столкнулся с аналогичной проблемой здесь: Android with Retrofit2 OkHttp3 - Multipart POST Error

я получил моя проблема решена после принятия @TommySM предложение. Если до сих пор неясно вам, я думаю, что это решение:

@Multipart 
@POST("jobDocuments/upload") 
Call<ResponseBody> upload(
    @Part MultipartBody.Part file, 
    @Part("folder") RequestBody folder, 
    @Part("name") RequestBody name); 

File file = new File(fileUri.getPath()); 

// Assume your file is PNG 
RequestBody requestFile = 
     RequestBody.create(MediaType.parse("image/png"), file); 

MultipartBody.Part fileData = 
     MultipartBody.Part.createFormData("file", fileName, requestFile); 

RequestBody folder = RequestBody.create(
     MediaType.parse("text/plain"), 
     "LeadDocuments"); 

RequestBody name = RequestBody.create(
     MediaType.parse("text/plain"), 
     fileName); 

// finally, execute the request 
Call<ResponseBody> call = service.upload(fileData, folder, name); 

Важной частью является использование MediaType.parse("text/plain") для MediaType параметра String (Я считаю, что ваш случай: Папка & параметр имя), с помощью okhttp3.MultipartBody.FORM является ошибка.

Смотрите эти скриншоты для сравнения:

1) проблематичных POST

enter image description here

2) Правильный POST

enter image description here

+0

Спасибо. Такая информация действительно полезна. –

+0

Выглядит хорошо, я постараюсь. – ahmadalibaloch