使用Retrofit2将文件上载到AWS S3预签名URL

时间:2017-09-01 00:13:31

标签: java android amazon-s3 retrofit2

我尝试使用预先签名的网址将文件上传到亚马逊的S3。我从服务器获取URL,生成URL&作为JSON对象的一部分发送给我。我将URL作为String获取,如下所示:

https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/ImageName?X-Amz-Security-Token=xxfooxx%2F%2F%2F%2F%2F%2F%2F%2F%2F%2Fxxbarxx%3D&X-Amz-Algorithm=xxAlgoxx&X-Amz-Date=20170831T090152Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=xxcredxx&X-Amz-Signature=xxsignxx

不幸的是,当我将它传递给Retrofit2时,它会修改String,试图将其变为URL。我设置了encoding=true,它解决了大部分问题,但并未完全解决。我知道String的工作原理。我已经在Postman& amp;得到一个成功的回应。

第一次我尝试将String(除了我作为baseUrl删除的内容)作为一个整体放入Path

public interface UpdateImageInterface {
    @PUT("{url}")
    Call<Void> updateImage(@Path(value="url", encoded=true) String url, Body RequestBody image);
}

主叫代码:

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/")
            .build();

    UpdateImageInterface imageInterface = retrofit.create(UpdateImageInterface.class);
    // imageUrl is "ImageName..."
    Call<Void> call = imageInterface.updateImage(imageUrl, requestFile);

这主要适用于&#39;?&#39; (在&#34; ImageName&#34;之后)转换为&#34;%3F&#34;。这会导致Bad Request / 400。

我的下一次尝试是使用Retrofit2创建一个查询,然后将整个String(带有多个查询)转储到查询中。

public interface UpdateImageInterface {
    @PUT("ImageName")
    Call<Void> updateProfilePhoto(@Query(value="X-Amz-Security-Token", encoded = true) String token, @Body RequestBody image);
}

主叫代码:

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/")
            .build();

    UpdateImageInterface imageInterface = retrofit.create(UpdateImageInterface.class);
    // imageUrl is "xxfooxx..."
    Call<Void> call = imageInterface.updateImage(imageUrl, requestFile);

这得到了&#39;?&#39;正确呈现,但所有&#39;&amp;&#39;变为&#34;%26&#34;

最后,我尝试在baseUrl()中传递整个字符串但是由于没有&#39; /&#39;这会产生IllegalArgumentException。最后。

我知道我可以解析预先签名的网址以进行多次查询&amp;将它们组装在Retrofit2中,因为我们应该进行查询,但我希望避免这种处理。

重述问题:

有没有办法轻松(没有繁重的String解析)使用Retrofit2将文件上传到带有预签名URL的S3?

2 个答案:

答案 0 :(得分:4)

在同事的帮助下,这是解决方案。

public interface UpdateImageInterface {
    @PUT
    Call<Void> updateImage(@Url String url, @Body RequestBody image);
}

致电代码:

    String CONTENT_IMAGE = "image/jpeg";

    File file = new File(localPhotoPath);    // create new file on device
    RequestBody requestFile = RequestBody.create(MediaType.parse(CONTENT_IMAGE), file);

    /* since the pre-signed URL from S3 contains a host, this dummy URL will
     * be replaced completely by the pre-signed URL.  (I'm using baseURl(String) here
     * but see baseUrl(okhttp3.HttpUrl) in Javadoc for how base URLs are handled
     */
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://www.dummy.com/")
        .build();

    UpdateImageInterface imageInterface = retrofit.create(UpdateImageInterface.class);
    // imageUrl is the String as received from AWS S3
    Call<Void> call = imageInterface.updateImage(imageUrl, requestFile);

Javadoc了解@Url(类Url)&amp; baseUrl()(类Retrofit.Builder)

MediaTypeOkHttp库中的一个类,通常与Retrofit(均来自Square)一起使用。有关传递给parse方法的常量的信息可以在Javadoc中找到。

答案 1 :(得分:0)

使用预先签名的网址直接上传到S3时使用以下内容。

 WebElement pointer = driver.findElement(By.xpath("/html/body/div[4]/div/div/section/div[2]/div[3]/div/div[1]"));

// Generic path to simulate the change in the xpath for the elements of the following pattern:
// WebElement tag1 = pointer.findElement(By.xpath("./div[1]/div/div[2]/a"));
// WebElement tag2 = pointer.findElement(By.xpath("./div[2]/div/div[2]/a"));

List<WebElement> linksList = pointer.findElements(By.xpath("./div/div/div[2]/a")); 
    for (WebElement link : linksList) {
        System.out.println(link.getAttribute("href"));
    }