我正在尝试将我的代码库从Retrofit 1.9升级到2.0版。在版本1.9中上传图像没有问题。但是,在将其更改为2.0版之后,我收到了S3响应错误。
这是我在Retrofit v1.9中上传图片的界面:
public interface IFileUploadAPI
{
@PUT("/{url}")
void uploadFile(@Path(value = "url", encode = false) String url, @Body() TypedFile file,
Callback<UploadFileResponse> callback);
}
我已将其更改为Retrofit v2.0上的以下代码:
public interface IFileUploadAPI
{
@PUT
Call<UploadFileResponse> uploadFile(@Url String url, @Body RequestBody file);
}
我正在以这种方式实施它。
public class MyFileUploadAPI
{
private IFileUploadAPI mService;
public MyFileUploadAPI()
{
final Retrofit adapter = new Retrofit.Builder() //
.baseUrl(MyAPIConstant.API_URL_BASE) // This URL will be ignored as we are using dynamic url. So no matters what it is.
.addConverterFactory(GsonConverterFactory.create(GsonUtils.getGson())) //
.client(ASDKApplication.getInstance().getOkHttpClient()) //
.build();
this.mService = adapter.create(IFileUploadAPI.class);
}
public void uploadFile(final String url, final String filePath, final String mimeType)
{
RequestBody file = RequestBody.create(MediaType.parse(mimeType), filePath);
Call<UploadFileResponse> call = mService.uploadFile(url, file);
call.enqueue(new Callback<HitchUploadFileResponse>()
{
@Override
public void onResponse(Call<UploadFileResponse> call, Response<UploadFileResponse> response)
{
UploadFileResponse uploadFileResponse = new UploadFileResponse();
if (response.isSuccessful() && response.body() != null)
{
uploadFileResponse = response.body();
}
// Rest of code...
}
@Override
public void onFailure(Call<UploadFileResponse> call, Throwable t)
{
Logger.error(TAG, "uploadFile.onFailure(), msg: " + t.getMessage());
}
}
}
}
因此,当用户点击Upload
按钮时,我调用一个API,它会返回一个我必须调用的URL。回应看起来像:
[{"uploadSignedURL":"https://my-account.s3.amazonaws.com/license/1000_front_1464988248.jpeg?AWSAccessKeyId=MY_ID\u0026Expires=1464991848\u0026Signature=NhStdEX8RH3J0uzvVa6h%2FvN6FZQ%3D","filePath":"license/1000_front_1464988248.jpeg","target":"driving_license_front_img"}]
最后响应上面的url调用(http状态代码403禁止):
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>MY_ID</AWSAccessKeyId><StringToSign>PUT
image/jpeg; charset=utf-8
1464991848
/my-account/license/1000_front_1464988248.jpeg</StringToSign><SignatureProvided>NhStdEX8RH3J0uzvVa6h/vN6FZQ=</SignatureProvided><StringToSignBytes>50 55 54 0a 0a 69 6d 61 67 65 2f 6a 70 65 67 3b 20 63 68 61 72 73 65 74 3d 75 74 66 2d 38 0b 31 34 36 34 39 39 31 38 34 38 0a 2f 6d 79 74 65 6b 73 69 3a 67 72 61 62 68 69 45 63 68 2f 6c 69 63 65 6e 73 65 2f 31 30 30 30 5f 66 72 6f 6e 74 5f 31 34 36 34 39 38 38 32 34 38 2e 6a 70 65 67</StringToSignBytes><RequestId>2D6D08FE4E34FCE5</RequestId><HostId>tpvmJdeRxtAzPxOk2zFwMF2Ne6hmNMkcaM9D7m/I13iynYGJyqtC0U72B2t41SDYfPBjCRTVyOY=</HostId></Error>
好的,我发现了什么是错的。
okhttp
正在将charset=utf-8
添加到我的contentType
中。因此我的contentType
就像这个contentType: image/jpeg; charset=utf-8
。我在Postman上测试并通过删除; charset=utf-8
我能够上传我的图像。
https://stackoverflow.com/a/25560731/513413说添加charset
的原因。这是因为我正在将路径传递给我的图像文件。你可以轻松改变
RequestBody file = RequestBody.create(MediaType.parse(mimeType), filePath);
至
RequestBody file = RequestBody.create(MediaType.parse(mimeType), new File(filePath));
还有一件更重要的事情。将图像上传到S3后,Amazon会返回空状态的HTTP状态代码200。所以你也必须改变界面。
public interface IFileUploadAPI
{
@PUT
Call<Void> uploadFile(@Url String url, @Body RequestBody file);
}