Модернизация 2 не может загрузить файл с двумя дополнительными отдельными строковыми параметрами
Прочитайте редактирование в нижней части вопроса для возможного альтернативного решения, пока решение не будет найдено.
Это успешный почтовый файл с двумя параметрами с помощью POSTMan. Я пытаюсь сделать то же самое с модификацией, но получаю BadRequest.
Настройки PostMan:
![введите описание изображения здесь]()
Сведения о связи в сети Chrome:
![введите описание изображения здесь]()
Теперь вот как я делаю это в 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(...);
Ответы
Ответ 1
Итак, надеюсь, что это не слишком поздно, и если это так - это может помочь кому-то еще:) мои 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 your show....
listener.getResult("Got it");
}
catch (Exception e)
{
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable throwable)
{
}
});
}
(Я использую прослушиватель, чтобы возвращать ответ обратного вызова в другую часть приложения (например, вызывающую активность)).
Это определенно отправляет файл/с и текстовое поле, другие проблемы, вероятно, будут связаны с сервером.
Надеюсь, что это поможет!
Ответ 2
Я столкнулся с аналогичной проблемой здесь: Android с Retrofit2 OkHttp3 - Ошибка многопоточного POST
У меня проблема была решена после принятия предложения @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
![введите описание изображения здесь]()
2) Исправить POST
![введите описание изображения здесь]()
Ответ 3
Используя Retrofit 2, вам нужно использовать классы OkHttps RequestBody или MultipartBody.Part и инкапсулировать ваш файл в тело запроса. Давайте посмотрим на определение интерфейса для загрузки файлов.
Вы видели https://futurestud.io/blog/retrofit-2-how-to-upload-files-to-server
Ответ 4
Интерфейс для доработки (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);
}
Класс ответа (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) {
}
});
}
Ошибка в полях из-за какой-либо из этих проблем сервера
Ответ 5
Похоже, что ваше определение сервиса неверно. Попробуйте
@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.