Lire le texte au bas de la question pour une solution de remplacement possible jusqu'à ce que la solution soit trouvée.}
C'est un fichier de publication réussi avec deux paramètres utilisant POSTMan. J'essaie de faire la même chose avec la modification mais reçois BadRequest.
Réglages PostMan:
Détails de publication sur le réseau Chrome:
Maintenant, voici comment je le fais dans Android mais en échouant:
Interface de service de modernisation:
@Multipart
@POST("jobDocuments/upload")
Call<ResponseBody> upload(@Part("file") MultipartBody.Part file,@Part("folder") MultipartBody.Part folder,@Part("name") MultipartBody.Part name);
Ceci est ma méthode @Background pour exécuter la requête réseau avec le service ci-dessus généré.
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());
}
Voici ma méthode Api Web:
[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");
}
S'il vous plaît, aidez là où je me trompe et comment y parvenir. Existe-t-il une alternative simple au retrofit?
[Edit] Ce code fonctionne correctement, grâce à 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(...);
J'ai rencontré un problème similaire ici: Android avec Retrofit2 OkHttp3 - Multipart POST Erreur
Mon problème a été résolu après avoir pris la suggestion de @TommySM. Si cela ne vous est pas encore clair, je pense que c'est la solution:
@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);
La partie importante est d’utiliser MediaType.parse("text/plain")
pour le paramètre MediaType
of String (je pense que votre cas est: paramètre folder & name), utiliser okhttp3.MultipartBody.FORM
est une erreur.
Voir ces captures d'écran pour la comparaison:
1) POST problématique
2) correct post
Donc, espérons qu'il n'est pas trop tard, et si c'est le cas - cela pourrait aider quelqu'un d'autre :) mes 2 centimes à ce sujet sont après avoir eu le même problème il y a quelque temps:
La définition de service, utilisant uniquement @Part
(modifiez les noms de champs en fonction des attentes de votre serveur)
//Single image MultiPart
@Multipart
@POST("user/imageupload")
Call<ResponseBody> upload(@Part("userfile") RequestBody file, @Part("userid") RequestBody description);
Et pour le tour de magie, je me réfère aux deux parties juste comme RequestBody
, en utilisant la fonction MediaType.parse()
à chacune avec son propre type, en s'appuyant sur la définition de @Multipart
pour la demande elle-même, aucun besoin de form-data
, les mêmes travaux pour plusieurs fichiers, et plusieurs champs:
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)
{
}
});
}
(J'utilise un écouteur pour renvoyer la réponse au rappel à une autre partie de l'application (par exemple, une activité d'appel)).
Ceci envoie définitivement le fichier/s et le champ de texte, d’autres problèmes proviendraient probablement du côté serveur.
J'espère que cela t'aides!
Interface pour la modernisation (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);
}
Classe de réponse (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;
}
}
Appel API depuis l'application
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) {
}
});
}
Erreur dans les champs, en raison de l'un de ces problèmes de serveur
Il semble que votre définition de service soit erronée. Essayer
@Multipart
@POST("jobDocuments/upload")
Call<ResponseBody> upload(@Part("file") MultipartBody.Part file,@Part("folder") RequestBody folder,@Part("name") RequestBody name);
et
RequestBody folder =
RequestBody.create(
MediaType.parse("multipart/form-data"), "LeadDocuments");
RequestBody name =
RequestBody.create(
MediaType.parse("multipart/form-data"), filename);
dans votre méthode @Background. Tout cela suppose que vous utilisez Retrofit2.