java - 如何使用二进制形式的 Retrofit 上传图像?

标签 java android retrofit2

我正在开发一个 Android 应用程序,它会发布一些带有用户签名的用户输入数据(使用签名板捕获签名并将其转换为 bmp 文件)。

现在,在发布整个数据之前,我需要请求服务器上传我的 Canvas 签名。所以服务器将回复两个 url(引用图片 1),分别是 put url 和 get url 现在我必须使用 PUT url 上传签名图像文件,整个过程通过 postman 成功,但我无法在 Android 应用程序上实现。 Put URl 的主体是二进制的,我选择一些随机图像文件。 作为引用,请参阅随附的屏幕截图 Pre Requesting the server for uploading imagePre Request body Put URL Params to upload image Put url headers to upload image Selecting an image as a binary body

Retrofit retrofit_image_upload=new Retrofit.Builder()
                                        .baseUrl(Aws_url) // base url retrive using Uri class using uri.getAuthority and concat with "https:/"
                                        .addConverterFactory(GsonConverterFactory.create())
                                        .build();
                ByteArrayOutputStream stream=new ByteArrayOutputStream();
                signature.compress(Bitmap.CompressFormat.PNG,100,stream);
                byte[] byteArray=stream.toByteArray();
                final RequestBody requestBody=RequestBody.create(MediaType.parse("application/octet-stream"),byteArray);

现在调用api并传递数据

                                Call<Object> image_upload_call= null;
                                try {
                                    image_upload_call = final_upload.aws_upload(path,auth,requestBody.contentLength(),x_amz_acl,AWSAccessKeyId,Expires,Signature_aws,requestBody);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }

上传图片接口(interface)

    @PUT("{Put_path}")
    Call<Object> aws_upload(@Path("Put_path") String path,
                            @Header("auth") String auth,
                            @Header("Content-Length") long length,
                            @Query("x-amz-acl") String x_amz,
                            @Query("AWSAccessKeyId") String awskey,
                            @Query("Expires") String Expires,
                            @Query("Signature") String Awssignature,
                            @Body RequestBody image);
}

当我使用此代码设置服务器不接受来自 Android 应用程序的文件,响应是错误代码 403,当我尝试从 postman 软件上传图像文件时,它工作正常。那么我该如何将其实现到 Android 应用程序中呢? 来自服务器的错误

    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>

最佳答案

数据准备部分代码对我来说看起来不错。但是您用于 PUT 请求的 URL 是错误的。

正如您在问题中提到的

before posting whole data I need to request server to upload my canvas signature. so server will reply with two urls

该 API 返回 2 个 URL。从这 2 个 URL 中,您选择第二个 URL 来上传文件。我希望到目前为止它在 Android 部分工作得很好。

现在,是时候上传文件了。您已从 API 获得了用于上传文件的完全限定 URL。只需将您的 BASE_URL 替换为您获得的第二个 URL。您应该使用 @Url 注释,而不是使用 @Path("Put_path") 注释。就像下面这样,

@PUT()   /* remove "{Put_path}" parameter*/
Call<Object> aws_upload(
    @Url String path,   /* replace @Path() with @Url */
    @Header("auth") String auth,
    @Header("Content-Length") long length,
    @Query("x-amz-acl") String x_amz,
    @Query("AWSAccessKeyId") String awskey,
    @Query("Expires") String Expires,
    @Query("Signature") String Awssignature,
    @Body RequestBody image);

说明

  1. 它是如何工作的?

假设您想访问以下网址

https://api.example.com/users/{user_id}

在 Retrofit 中,您声明一个 BASE_URL 并为其分配值 https://api.example.com/。在您的服务接口(interface)文件中,您声明一个如下所示的方法

@GET("users/{user_id}")
Call<UserModel> fetchUserById(@Path("user_id") int userId);

每当您调用上述方法时,它都会构建一个类似

的 URL
https://api.example.com/users/100

从上面的例子中我们了解到的是@GET()@POST()@PUT() @DELETE() 等方法接受部分 URL,Retrofit 客户端将为您生成完全限定的 URL。

  • 如果您想从 Retrofit 客户端访问 BASE_URL 以外的 URL,该怎么办?
  • 在这种情况下,我们使用 Retrofit 的 @Url 注释。它将完全替换当前请求的 BASE_URL。

    我将演示与上面相同的示例,但带有 @Url 注释。

    @GET()  // notice the difference you don't need to pass partial path here
    Call<UserModel> fetchUserById(@Url String url);
    

    这次我将在调用方法或 Activity/Fragment 中对完全限定的 URL 进行硬编码。

    String overrideUrl = "https://api.example.com/users/200"; // prepare fully qualified url
    
    SomeServiceInterface service = ...
    
    Call<UserModel> call = service.fetchUserById(overrideUrl);  // pass it to method as an argument
    
    call.enqueue(/* callback implementation here */);
    

    关于java - 如何使用二进制形式的 Retrofit 上传图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58679955/

    相关文章:

    android - Kotlin 中的错误(改造)预期为 BEGIN_ARRAY,但在第 1 行第 2 列路径 $ 处为 BEGIN_OBJECT

    android - 如何使用改造 2 发送帖子对象

    java - JPQL(Hibernate 实现)选择与连接问题

    java - 在myBatis中调用java方法生成SQL查询

    android - 当我返回父 Fragment 的旧实例时,FragmentStatePagerAdapter 无法再次加载 fragment

    android - 如何保持位图中的纵横比可绘制

    java - NetBeans 的两个 JPA 持久性单元具有相同的表名

    java - 更改 JDK 以从构建 xml 中运行 <ANT> 任务

    android - 如何找到android设备的LAN ip地址?

    android - 使用 Retrofit2 发送 json 和文件