【问题标题】:Error uploading file with Retrofit 2使用 Retrofit 2 上传文件时出错
【发布时间】:2017-07-02 03:25:36
【问题描述】:

我正在工作的系统有一个端点,它接收文件图片以设置用户的个人资料图片。如果我尝试通过 Postman 发送,一切正常:

当我尝试使用改造从我的应用程序上传它时,它总是失败。代码+堆栈跟踪如下:

服务器端代码:

begin
         user = User.find(doorkeeper_token.resource_owner_id)
         image = params[:image]
         attachment = {
             :filename => image[:filename],
             :type => image[:type],
             :headers => image[:head],
             :tempfile => image[:tempfile]
         }

         image_link = ""
         if params[:upload_type] == "profile"
           user.profile_image = ActionDispatch::Http::UploadedFile.new(attachment)
           image_link = get_image_path(user.id,params[:upload_type],"original",attachment[:filename])
           user.image_profile_original = get_image_path(user.id,params[:upload_type],"original",attachment[:filename])
           user.image_profile_large = get_image_path(user.id,params[:upload_type],"large",attachment[:filename])

 /*e22*/
    @Multipart
    @POST("user/upload_image")
    fun uploadUserImage(@Header("Authorization") authHeader: String,  @Part("upload_type") description: RequestBody, @Part file: MultipartBody.Part): Call<ResponseWrapper>

 fun uploadUserImage(image: Uri) {
        val source = File(image.path)
        val requestFile = RequestBody.create(MediaType.parse(getContext().contentResolver.getType(image)), source)
        val body = MultipartBody.Part.createFormData("image", "profile", requestFile)
        val description = RequestBody.create(okhttp3.MultipartBody.FORM, "profile")
        mMessenger.uploadUserImage(getAuthorizationHeader(), description, body).enqueue(ResponseWrapperCallback(EventCatalog.e0022))
    }

请求响应:

E/ResponseWrapperCallback: Failed processing request: profile: open failed: ENOENT (No such file or directory)
E/ResponseWrapperCallback: HTTP request mapped to event e0022 finished with error

编辑 1

我确实认为这个错误与 File 对象的实例化方式有关。如果我直接从 Uri 创建文件,它的真实路径似乎不会发送到服务器。我说由于上面的错误日志,它说它没有在检索到的设备的 Uri 上找到文件。我尝试从 Uri 中提取文件的真实路径,但是,服务器的错误日志已更改为:

/storage/emulated/0/Marvel/Media/Characters/Adam Warlock.jpeg: open failed: EACCES (Permission denied)

我用真实文件路径实例化 File 对象的方式是这样的:

   private fun getRealPathFromURI(contentURI: Uri): String {
        val result: String
        val cursor = getContext().contentResolver.query(contentURI, null, null, null, null)
        if (cursor == null) {
            result = contentURI.path
        } else {
            cursor.moveToFirst()
            val idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA)
            result = cursor.getString(idx)
            cursor.close()
        }
        return result
    }

//....

val source = File(getRealPathFromURI(Uri))

编辑 2

根据用户 Anurag Singh 的要求,以下是清单和操作系统信息:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.1"

    defaultConfig {
        applicationId "***"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
        vectorDrawables.useSupportLibrary = true
    }
}

编辑 3

这是 Postman 生成的代码,运行良好!

OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");

RequestBody body = RequestBody.create(mediaType, "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"image\"; filename=\"sample 2.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"upload_type\"\r\n\r\nprofile\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");

Request request = new Request.Builder()
  .url("http://********/user/upload_image")
  .post(body)
  .addHeader("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW")
  .addHeader("authorization", "Bearer ******")
  .addHeader("cache-control", "no-cache")
  .addHeader("postman-token", "******")
  .build();

Response response = client.newCall(request).execute();

【问题讨论】:

  • post,source的值。
  • 嗨@AnuragSingh 你想看它的哪一部分?我可以注意到,如果我直接从 Uri 创建文件,它的真实路径不会发送到服务器。当我尝试从 Uri 提取文件的真实路径并从中创建对象时,服务错误已更改为:/storage/emulated/0/Marvel/Media/Characters/Adam Warlock.jpeg:打开失败:EACCES(权限被拒绝)
  • source 表示文件路径。我想检查如何从 URI 获取路径。现在基于与权限相关的新错误。让我知道您正在测试的设备操作系统版本,发布清单权限和以下 compileSdkVersion、minSdkVersion、targetSdkVersion 的值。谢谢
  • 尝试添加权限。同时让我做更多的分析。如果你拦截底层的 OkHttp 客户端,还要确保为文件上传设置的 Content-Type 设置为 multipart/form-data 而不是 application/json。
  • 那我应该把它作为答案发布吗?

标签: android ruby-on-rails retrofit multipartform-data retrofit2


【解决方案1】:

尝试在AndroidManifest.xml中添加以下权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>.

从 Android 6.0(API 级别 23)开始,用户在应用运行时授予应用权限,而不是在安装应用时。 Requesting Permissions at Run Time

【讨论】:

  • 感谢您抽出宝贵时间帮助我解决这个不太直接的问题
猜你喜欢
  • 2016-09-04
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 2022-11-11
  • 2017-05-14
  • 2017-03-28
  • 2016-11-09
  • 2016-02-16
相关资源
最近更新 更多