Lesen Sie die Bearbeitung am Ende der Frage nach einer möglichen alternativen Lösung, bis die Lösung gefunden wird.
Dies ist eine erfolgreiche Post-Datei mit zwei Parametern, die POSTMan verwenden. Ich versuche dasselbe mit dem Retrofit zu tun, erhalte aber BadRequest.
PostMan-Einstellungen:
Jetzt mache ich das in Android, scheitere aber:
Retrofit Service Interface:
@Multipart
@POST("jobDocuments/upload")
Call<ResponseBody> upload(@Part("file") MultipartBody.Part file,@Part("folder") MultipartBody.Part folder,@Part("name") MultipartBody.Part name);
Dies ist meine @ Background-Methode, um die Netzwerkanforderung mit dem obigen Dienst auszuführen
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());
}
Hier ist meine Web-API-Methode:
[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");
}
Bitte helfen Sie mir, wo ich mich irre und wie ich das erreichen kann. Gibt es eine einfache Alternative zum Nachrüsten?
[Edit] Dieser Code funktioniert erfolgreich. Danke an 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(...);
Ich hatte hier ein ähnliches Problem: Android mit Retrofit2 OkHttp3 - Multipart POST Fehler
Ich habe mein Problem gelöst, nachdem ich den Vorschlag von @TommySM genommen hatte. Wenn Ihnen noch unklar ist, denke ich, dass dies die Lösung ist:
@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);
Der wichtige Teil ist die Verwendung von MediaType.parse("text/plain")
für MediaType
des String-Parameters (ich glaube, Ihr Fall ist: folder & name -Parameter). okhttp3.MultipartBody.FORM
ist ein Fehler.
Sehen Sie sich diese Screenshots zum Vergleich an:
1) Problematischer POST
2) Korrigieren Sie den POST
Ich hoffe, es ist nicht zu spät, und wenn ja, dann könnte es jemand anderem helfen :) Meine 2 Cent darüber sind nach einer Weile das gleiche Problem:
Die Service-Definition, die nur @Part
verwendet (ändern Sie die Feldnamen entsprechend den Erwartungen Ihres Servers)
//Single image MultiPart
@Multipart
@POST("user/imageupload")
Call<ResponseBody> upload(@Part("userfile") RequestBody file, @Part("userid") RequestBody description);
Und für den Zaubertrick verweise ich auf beide Teile nur als RequestBody
, benutze MediaType.parse()
für jeden mit seinem eigenen Typ, stütze mich auf die @Multipart
-Definition für die Anfrage selbst, keine Notwendigkeit für form-data
-Sachen, dasselbe gilt für mehrere Dateien und mehrere Felder:
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)
{
}
});
}
(Ich verwende einen Listener, um die Rückrufantwort an einen anderen Teil der App zurückzugeben (z. B. eine aufrufende Aktivität).).
Dies sendet definitiv die Datei (en) und das Textfeld, andere Probleme würden wahrscheinlich von der Serverseite stammen.
Hoffe das hilft!
Bei Verwendung von Retrofit 2 müssen Sie entweder die RequestBody- oder die MultipartBody.Part-Klasse von OkHttp verwenden und Ihre Datei in einen Anforderungstext einkapseln. Schauen wir uns die Schnittstellendefinition für Dateiuploads an . Kennen Sie https://futurestud.io/blog/retrofit-2-how-to-upload-files-to-server
Schnittstelle für Retrofit (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);
}
Antwortklasse (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-Aufruf von Anwendung
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) {
}
});
}
Fehler in Feldern wegen eines dieser Serverprobleme
Es scheint, dass Ihre Service-Definition falsch ist. Versuchen
@Multipart
@POST("jobDocuments/upload")
Call<ResponseBody> upload(@Part("file") MultipartBody.Part file,@Part("folder") RequestBody folder,@Part("name") RequestBody name);
und
RequestBody folder =
RequestBody.create(
MediaType.parse("multipart/form-data"), "LeadDocuments");
RequestBody name =
RequestBody.create(
MediaType.parse("multipart/form-data"), filename);
in Ihrer @Background-Methode. Dies alles setzt voraus, dass Sie Retrofit2 verwenden.