Retrofit 2无法上传带有两个额外字符串参数的文件

ahm*_*och 15 android file-upload android-networking retrofit retrofit2

在问题的底部阅读编辑以寻找可能的替代解决方案,直到找到解决方案.

这是一个成功的帖子文件,其中包含两个使用POSTMan的参数.我试图通过改造来做同样的事但收到BadRequest.

邮差设置:

在此输入图像描述

Chrome网络帖子详情: 在此输入图像描述

现在我在Android中如何做到这一点但失败了:

改造服务接口:

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

这是我的@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());
    }
Run Code Online (Sandbox Code Playgroud)

这是我的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");
    }
Run Code Online (Sandbox Code Playgroud)

请帮助我错了,如何实现这一目标,是否有任何简单的替代改造?

[编辑] 此代码正常运行,感谢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(...);
Run Code Online (Sandbox Code Playgroud)

Shu*_*Tee 11

我在这里面临类似的问题: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);
Run Code Online (Sandbox Code Playgroud)

最重要的部分是使用MediaType.parse("text/plain")MediaType字符串参数(我相信你的情况是:文件夹和名称参数),使用okhttp3.MultipartBody.FORM是错误的.

请参阅以下屏幕截图进行比较:

1)有问题的POST

在此输入图像描述

2)正确的POST

在此输入图像描述


Tom*_*ySM 7

所以,希望它不会太晚,如果是这样 - 它可能会帮助其他人:)我的2美分关于这个问题是在一段时间之后遇到同样的问题:

服务定义,@Part仅使用(根据服务器期望的内容修改字段名称)

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

而对于魔术技巧,我指的是两个部分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)
        {

        }
    });
}
Run Code Online (Sandbox Code Playgroud)

(我使用监听器将回调响应返回给应用程序的不同部分(例如,调用活动)).

这肯定会发送文件和文本字段,其他问题可能源于服务器端.

希望这可以帮助!


Joh*_*wUs 0

看起来您的服务定义是错误的。尝试

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

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

在你的 @Background 方法中。这一切都假设您使用的是 Retrofit2。