And*_*n K 8 rest android amazon-s3 retrofit
我正在尝试Image从我的Android APP上传到Amazon AWS S3,我需要使用AWS Restful API.
我正在使用Retrofit 2来提出请求.
我的应用程序与Amazon S3成功连接并按预期执行请求,但是当我尝试Image从Bucket查看时,图片无法打开.我下载Image到我的电脑并尝试打开但仍然收到图像已损坏的消息.
让我们看看我的完整代码.
我的Gradle依赖项
compile 'com.squareup.retrofit:retrofit:2.0.0-beta1'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta1'
compile 'net.danlew:android.joda:2.8.2'
Run Code Online (Sandbox Code Playgroud)
这里创建了一个文件并启动了请求
File file = new File(mCurrentPhotoPath);
RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"), file);
uploadImage(body, "photo_name.jpeg");
Run Code Online (Sandbox Code Playgroud)
改造界面
public interface AwsS3 {
@Multipart
@PUT("/{Key}")
Call<String> upload(@Path("Key") String Key,
@Header("Content-Length") long length,
@Header("Accept") String accept,
@Header("Host") String host,
@Header("Date") String date,
@Header("Content-type") String contentType,
@Header("Authorization") String authorization,
@Part("Body") RequestBody body);
}
Run Code Online (Sandbox Code Playgroud)
Utils类用于挂载凭据
public class AWSOauth {
public static String getOAuthAWS(Context context, String fileName) throws Exception{
String secret = context.getResources().getString(R.string.s3_secret);
String access = context.getResources().getString(R.string.s3_access_key);
String bucket = context.getResources().getString(R.string.s3_bucket);
return gerateOAuthAWS(secret, access, bucket,fileName);
}
private static String gerateOAuthAWS(String secretKey, String accessKey, String bucket, String imageName) throws Exception {
String contentType = "image/jpeg";
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").withLocale(Locale.US);
String ZONE = "GMT";
DateTime dt = new DateTime();
DateTime dtLondon = dt.withZone(DateTimeZone.forID(ZONE)).plusHours(1);
String formattedDate = dtLondon.toString(fmt);
String resource = "/" + bucket + "/" + imageName;
String stringToSign = "PUT" + "\n\n" + contentType + "\n" + formattedDate + "\n" + resource;
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1"));
String signature = ( Base64.encodeToString(hmac.doFinal(stringToSign.getBytes("UTF-8")), Base64.DEFAULT)).replaceAll("\n", "");
String oauthAWS = "AWS " + accessKey + ":" + signature;
return oauthAWS;
}
}
Run Code Online (Sandbox Code Playgroud)
最后是提出请求的方法
public void uploadImage(RequestBody body, String fileName){
String bucket = getString(R.string.s3_bucket);
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl("http://" + bucket + ".s3.amazonaws.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
AwsS3 service = restAdapter.create(AwsS3.class);
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").withLocale(Locale.US);
String ZONE = "GMT";
DateTime dt = new DateTime();
DateTime dtLondon = dt.withZone(DateTimeZone.forID(ZONE)).plusHours(1);
String formattedDate = dtLondon.toString(fmt);
try {
String oauth = AWSOauth.getOAuthAWS(getApplicationContext(), fileName);
Call<String> call = service.upload(fileName, body.contentLength(), "/**", bucket + ".s3.amazonaws.com", formattedDate, body.contentType().toString(), oauth, body);
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Response<String> response) {
Log.d("tag", "response : " + response.body());
}
@Override
public void onFailure(Throwable t) {
Log.d("tag", "response : " + t.getMessage());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
我感谢任何帮助,提前谢谢!
小智 9
我使用了 Retrofit 2 解决方案,我使用Body而不是Part用于您RequestBody的界面
@PUT("")
Call<String> nameAPI(@Url String url, @Body RequestBody body);
Run Code Online (Sandbox Code Playgroud)
和java代码
// Prepare image file
File file = new File(pathImg);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"), file);
Call<String> call = SingletonApiServiceS3.getInstance().getService().nameAPI(
path,
requestBody
);
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, final Response<String> response) {
if (response.isSuccessful()) {
// Your handling
} else {
// Your handling
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(getContext(), "onFailure : "+t.getMessage().toString(),Toast.LENGTH_SHORT).show();
}
});
Run Code Online (Sandbox Code Playgroud)
小智 5
我有同样的问题,当我使用Fiddler检查HTTP请求内容时,我发现改进2.0.0 beta1与1.9.0有所不同.
在我的问题中,不同的HTTP请求内容阻止服务器获取正确的数据.
为了生成相同的HTTP请求内容,我使用retrofit 2.0.0 deta1执行后续步骤.
在改造服务中,为http请求添加表单数据头;
@Headers("Content-Type: multipart/form-data;boundary=95416089-b2fd-4eab-9a14-166bb9c5788b")
Run Code Online (Sandbox Code Playgroud)
int retrofit 2.0.0 deta1,标题使用@Multipart将得到这样的数据:
内容类型:multipart/mixed
由于聋人的价值是混合的,没有边界标题.
不要使用@Multipart上传文件,只需使用@Body RequestBody
如果您使用@Multipart请求服务器,则必须通过param(文件)
@Part(key),那么你将遇到一个新问题.可能是改造2.0.0beta1有一个BUG ...,@Multipart用1.9.0生成一个错误的http请求编译.
调用方法时,需要将MultipartRequestBody传递给@Body RequestBody
使用MultipartBuilder创建MultipartRequestBody,当你新的MultipartBuilder,称之为consturt:
new MultipartBuilder("95416089-b2fd-4eab-9a14-166bb9c5788b")
Run Code Online (Sandbox Code Playgroud)
你设置了param int @headers(boundary=)
builder.addFormDataPart(String name, String filename, RequestBody value)
Run Code Online (Sandbox Code Playgroud)
此方法将有助于形成如下数据的HTTP请求内容:
内容处理:表格数据; NAME = "imgFile"; filename ="IMG_20150911_113029.jpg"内容类型:图像/ jpg内容长度:1179469
RequestBody value是您在代码中生成的值.
我只是临时解决这个问题.
希望可以帮到你!
RequestBody avatarBody = RequestBody.create(MediaType.parse("image"),file);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), avatarBody);
@Multipart
@POST(url)
Call<ResponseBody> uploadImageAmazon(
@Part MultipartBody.Part filePart);
Run Code Online (Sandbox Code Playgroud)
我有同样的经历,并通过https://github.com/square/retrofit/issues/2424这个解决方案解决了它