Retrofit 2 图片上传成功但图片上传为损坏的文件
Retrofit 2 image upload success but image uploads as corrupted file
事情是这样的,文件作为 "photo.png" 成功上传,但是当我从浏览器打开照片时,照片已损坏。当我下载照片在我的电脑本地打开时,照片损坏了。
不知道为什么。
改造终点如下:
@Multipart
@POST("alerts/{alertId}/photo/")
Call<Object> uploadPhotoStill(@Header("Authorization") String credentials, @Path("alertId") int alertId,
@Part("photo\"; filename=\"picture_taken.jpeg\" ") RequestBody photo);
我是这样使用它的:我正在抓取用相机对象拍照后返回的字节数组。
private void initCamera() {
if (camera == null) {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
Camera.Parameters params = camera.getParameters();
params.setPictureFormat(ImageFormat.JPEG);
camera.setParameters(params);
}
}
/**
* Called when image data is available after a picture is taken.
* The format of the data depends on the context of the callback
* and {@link Camera.Parameters} settings.
*
* @param data a byte array of the picture data
* @param camera the Camera service object
*/
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken() called with: " + "data = [" + Arrays.toString(data) + "], camera = [" + camera + "]");
handleTakenStill(data);
}
private void handleTakenStill(byte[] data) {
Log.d(TAG, "handleTakenStill() was called");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"), data);
havenApi.uploadPhotoStill(Utils.encodeUserCredentials(), getCurrentAlert().getId(), requestBody).enqueue(new Callback<Object>() {
@Override
public void onResponse(Response<Object> response, Retrofit retrofit) {
if (response.isSuccess()) {
Log.d(TAG, "handleTakenStill.onResponse success: " + response.body().toString());
} else {
Log.e(TAG, "handleTakenStill.onResponse error: " + response.message());
}
}
@Override
public void onFailure(Throwable t) {
Utils.logOnFailureRequest(TAG, t);
}
});
}
上传照片后总是调用成功。但是照片总是上传损坏,我不知道为什么。
1) 按照评论中的说明检查照片类型。有时swith到JPG格式解决问题。
2) 尝试将文件或文件路径作为 RequestBody 的参数(RequestBode 对象的另一个构造函数)
我使用下面的代码没有问题,但是我将文件作为表单数据发送:
@Multipart
@POST("/api/tour/upload")
Call<MainFileModel> uploadTourFiles(@PartMap Map<String, RequestBody> params);
File mainFile = new File(fileLoad.getFile());
Map params = new Map<>();
params.put("file\"; filename=\"" + mainFile.getName(),
RequestBody.create(MediaType.parse("multipart/form-data"), mainFile));;
//And Make call here!
我从来没有让这个与改造一起工作。但我能够用 OkHttp 做到这一点。
如果您想知道解决方案是什么:
/**
* Called when image data is available after a picture is taken.
* The format of the data depends on the context of the callback
* and {@link Camera.Parameters} settings.
*
* @param data a byte array of the picture data
* @param camera the Camera service object
*/
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken() called with: " + "data = [" + Arrays.toString(data) + "], camera = [" + camera + "]");
handleTakenStill(data);
}
private void handleTakenStill(byte[] data) {
Log.d(TAG, "handleTakenStill() was called");
Observable.create(uploadPhoto(data))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<com.squareup.okhttp.Response>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted() was called");
}
@Override
public void onError(Throwable e) {
Utils.logOnFailureRequest(TAG, e);
}
@Override
public void onNext(com.squareup.okhttp.Response response) {
if (response.isSuccessful()) {
Log.d(TAG, "handleTakenStill.onResponse success: " + response.body().toString());
} else {
Log.e(TAG, "handleTakenStill.onResponse error: " + response.message());
}
}
});
}
@NonNull
private Observable.OnSubscribe<com.squareup.okhttp.Response> uploadPhoto(final byte[] data) {
return new Observable.OnSubscribe<com.squareup.okhttp.Response>() {
@Override
public void call(Subscriber<? super com.squareup.okhttp.Response> subscriber) {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new MultipartBuilder().type(MultipartBuilder.FORM)
.addFormDataPart("camera", "picture_taken.jpg", RequestBody.create(MediaType.parse("image/jpeg"), data))
.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.addHeader("content-type", "multipart/form-data")
.addHeader("authorization", Utils.encodeUserCredentials())
.addHeader("accept", "application/json")
.addHeader("cache-control", "no-cache")
.build();
try {
com.squareup.okhttp.Response response = client.newCall(request).execute();
subscriber.onNext(response);
subscriber.onCompleted();
if (!response.isSuccessful()) {
subscriber.onError(new Exception("Error uploading photo"));
}
} catch (IOException e) {
subscriber.onError(e);
}
}
};
}
我也有这个问题。我没有使用 MultiPart 表单,而是为适合我的图像数据使用了一个简单的 RequestBody。我在 Android 项目中使用 Kotlin。
我的改造API:
interface FilesApi {
@PUT("/files/attachments/{parentId}")
fun uploadAttachment(
@Path("parentId") parentId: String,
@Header("Content-Type") contentType: String,
@Header("Name") name: String,
@Header("Description") description: String?,
@Body image: RequestBody
): Single<Response<FileUploadResponse>>
}
正在创建请求对象:
imageData 变量是一个 ByteArray
val requestFile = imageData.toRequestBody(contentType.toMediaTypeOrNull(), 0, imageData.size)
return filesApi.uploadAttachment(parentId, contentType, name, description, requestFile)
.map { response ->
response.code()
response.errorBody()
response.body()?.Result
}
事情是这样的,文件作为 "photo.png" 成功上传,但是当我从浏览器打开照片时,照片已损坏。当我下载照片在我的电脑本地打开时,照片损坏了。
不知道为什么。
改造终点如下:
@Multipart
@POST("alerts/{alertId}/photo/")
Call<Object> uploadPhotoStill(@Header("Authorization") String credentials, @Path("alertId") int alertId,
@Part("photo\"; filename=\"picture_taken.jpeg\" ") RequestBody photo);
我是这样使用它的:我正在抓取用相机对象拍照后返回的字节数组。
private void initCamera() {
if (camera == null) {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
Camera.Parameters params = camera.getParameters();
params.setPictureFormat(ImageFormat.JPEG);
camera.setParameters(params);
}
}
/**
* Called when image data is available after a picture is taken.
* The format of the data depends on the context of the callback
* and {@link Camera.Parameters} settings.
*
* @param data a byte array of the picture data
* @param camera the Camera service object
*/
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken() called with: " + "data = [" + Arrays.toString(data) + "], camera = [" + camera + "]");
handleTakenStill(data);
}
private void handleTakenStill(byte[] data) {
Log.d(TAG, "handleTakenStill() was called");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"), data);
havenApi.uploadPhotoStill(Utils.encodeUserCredentials(), getCurrentAlert().getId(), requestBody).enqueue(new Callback<Object>() {
@Override
public void onResponse(Response<Object> response, Retrofit retrofit) {
if (response.isSuccess()) {
Log.d(TAG, "handleTakenStill.onResponse success: " + response.body().toString());
} else {
Log.e(TAG, "handleTakenStill.onResponse error: " + response.message());
}
}
@Override
public void onFailure(Throwable t) {
Utils.logOnFailureRequest(TAG, t);
}
});
}
上传照片后总是调用成功。但是照片总是上传损坏,我不知道为什么。
1) 按照评论中的说明检查照片类型。有时swith到JPG格式解决问题。
2) 尝试将文件或文件路径作为 RequestBody 的参数(RequestBode 对象的另一个构造函数)
我使用下面的代码没有问题,但是我将文件作为表单数据发送:
@Multipart
@POST("/api/tour/upload")
Call<MainFileModel> uploadTourFiles(@PartMap Map<String, RequestBody> params);
File mainFile = new File(fileLoad.getFile());
Map params = new Map<>();
params.put("file\"; filename=\"" + mainFile.getName(),
RequestBody.create(MediaType.parse("multipart/form-data"), mainFile));;
//And Make call here!
我从来没有让这个与改造一起工作。但我能够用 OkHttp 做到这一点。
如果您想知道解决方案是什么:
/**
* Called when image data is available after a picture is taken.
* The format of the data depends on the context of the callback
* and {@link Camera.Parameters} settings.
*
* @param data a byte array of the picture data
* @param camera the Camera service object
*/
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken() called with: " + "data = [" + Arrays.toString(data) + "], camera = [" + camera + "]");
handleTakenStill(data);
}
private void handleTakenStill(byte[] data) {
Log.d(TAG, "handleTakenStill() was called");
Observable.create(uploadPhoto(data))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<com.squareup.okhttp.Response>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted() was called");
}
@Override
public void onError(Throwable e) {
Utils.logOnFailureRequest(TAG, e);
}
@Override
public void onNext(com.squareup.okhttp.Response response) {
if (response.isSuccessful()) {
Log.d(TAG, "handleTakenStill.onResponse success: " + response.body().toString());
} else {
Log.e(TAG, "handleTakenStill.onResponse error: " + response.message());
}
}
});
}
@NonNull
private Observable.OnSubscribe<com.squareup.okhttp.Response> uploadPhoto(final byte[] data) {
return new Observable.OnSubscribe<com.squareup.okhttp.Response>() {
@Override
public void call(Subscriber<? super com.squareup.okhttp.Response> subscriber) {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new MultipartBuilder().type(MultipartBuilder.FORM)
.addFormDataPart("camera", "picture_taken.jpg", RequestBody.create(MediaType.parse("image/jpeg"), data))
.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.addHeader("content-type", "multipart/form-data")
.addHeader("authorization", Utils.encodeUserCredentials())
.addHeader("accept", "application/json")
.addHeader("cache-control", "no-cache")
.build();
try {
com.squareup.okhttp.Response response = client.newCall(request).execute();
subscriber.onNext(response);
subscriber.onCompleted();
if (!response.isSuccessful()) {
subscriber.onError(new Exception("Error uploading photo"));
}
} catch (IOException e) {
subscriber.onError(e);
}
}
};
}
我也有这个问题。我没有使用 MultiPart 表单,而是为适合我的图像数据使用了一个简单的 RequestBody。我在 Android 项目中使用 Kotlin。
我的改造API:
interface FilesApi {
@PUT("/files/attachments/{parentId}")
fun uploadAttachment(
@Path("parentId") parentId: String,
@Header("Content-Type") contentType: String,
@Header("Name") name: String,
@Header("Description") description: String?,
@Body image: RequestBody
): Single<Response<FileUploadResponse>>
}
正在创建请求对象:
imageData 变量是一个 ByteArray
val requestFile = imageData.toRequestBody(contentType.toMediaTypeOrNull(), 0, imageData.size)
return filesApi.uploadAttachment(parentId, contentType, name, description, requestFile)
.map { response ->
response.code()
response.errorBody()
response.body()?.Result
}