Retrofit(2.0 beta2) 分段文件上传不起作用
Retrofit(2.0 beta2) Multipart file upload doesn't work
我正在使用 Square Retrofit 版本 2.0 beta2。我已尝试按照 this tutorial .我正在尝试将位图图像上传到服务器,但不知何故代码无法正常工作。我已经尝试使用 postman 测试我的服务器,我能够 post 照片甚至能够检索它。这是我的烧瓶控制器。
@app.route('/api/photo/user/<int:user_id>', methods=["POST"])
def post_user_photo(user_id):
app.logger.info("post_user_photo=> user_id:{}, photo: {}".format(
user_id,
request.files['photo'].filename,
))
user = User.query.get_or_404(user_id)
try:
user.photo = request.files['photo'].read()
except Exception as e:
app.logger.exception(e)
db.session.rollback()
raise
db.session.commit()
return "", codes.no_content
我已经使用 postman 来测试我的控制器,这里是 postman 生成的请求。
POST /api/photo/user/5 HTTP/1.1
Host: blooming-cliffs-9672.herokuapp.com
Cache-Control: no-cache
Postman-Token: 8117fb79-4781-449d-7d22-237c49b53389
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="photo"; filename="sfsu.jpg"
Content-Type: image/jpeg
----WebKitFormBoundary7MA4YWxkTrZu0gW
我已经定义了改造服务和上传图像,这是我的 Android 代码。接口部分
@Multipart
@POST("/api/photo/user/{userId}")
Call<Void> uploadUserProfilePhoto(@Path("userId") Integer userId, @Part("photo") RequestBody photo);
此处为客户端构建器部分
public static BeamItService getService(){
if (service == null) {
OkHttpClient client = new OkHttpClient();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
HttpLoggingInterceptor interceptor2 = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
client.interceptors().add(interceptor);
client.interceptors().add(interceptor2);
service = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build().create(BeamItService.class);
}
return service;
}
这里是 Android activity 尝试上传位图的代码。
private void uploadProfilePhoto(){
BeamItService service = BeamItServiceTransport.getService();
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpeg");
byte [] data = BitmapUtility.getBitmapToBytes(((BitmapDrawable) ivProfilePhoto.getDrawable()).getBitmap());
Log.d(TAG, String.format("Profile detals => user_id: %d, size of data: %d", 5, data.length));
RequestBody requestBody1 = RequestBody.create(MEDIA_TYPE_PNG,
data);
Log.d(TAG, "requestBody: " + requestBody1.toString());
RequestBody requestBody2 = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(Headers.of("Content-Disposition", "form-data; name=\"photo\"; filename=\"t.jpg\""),
requestBody1)
.build();
Log.d(TAG, "requestBody: " + requestBody2.toString());
// ProfileDetails profileDetails = new DBHelper(this).fetchProfileDetails();
Call<Void> call = service.uploadUserProfilePhoto(5, requestBody2);
call.enqueue(new ProfilePhotoUploadCallback());
}
private class ProfilePhotoUploadCallback implements Callback<Void> {
@Override
public void onResponse(Response<Void> response, Retrofit retrofit) {
Log.d(TAG, String.format("ProfilePhotoUploadCallback=> code: %d", response.code()));
}
@Override
public void onFailure(Throwable t) {
}
}
但是上传失败,flask app returns每次都是状态码400。我试图将断点放在烧瓶应用程序中,但请求甚至没有到达那里。
这是服务器日志
2015-11-02T06:05:42.288574+00:00 heroku[router]: at=info method=POST path="/api/photo/user/5" host=blooming-cliffs-9672.herokuapp.com request_id=2cc8b6c8-f12a-4e4b-8279-cedfc39712f2 fwd="204.28.113.240" dyno=web.1 connect=1ms service=88ms status=400 bytes=347
2015-11-02T06:05:42.209347+00:00 app[web.1]: [2015-11-02 06:05:42 +0000] [11] [DEBUG] POST /api/photo/user/5
我也尝试启用改造拦截器并记录请求和响应,但我没有得到整个 POST 请求正文。这是 Android 日志。
11-02 00:24:22.119 3904-4382/com.contactsharing.beamit D/OkHttp: --> POST /api/photo/user/5 HTTP/1.1
11-02 00:24:22.119 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Type: multipart/form-data; boundary=4031e177-0e4b-4f16-abe8-20c54e506846
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Length: 17171
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Host: blooming-cliffs-9672.herokuapp.com
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Connection: Keep-Alive
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Accept-Encoding: gzip
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: User-Agent: okhttp/2.6.0-SNAPSHOT
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: --> END POST
11-02 00:24:22.179 3904-4537/com.contactsharing.beamit I/DBHelper: Updated row: 1
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: <-- HTTP/1.1 400 BAD REQUEST (195ms)
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Connection: keep-alive
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Server: gunicorn/19.3.0
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Date: Mon, 02 Nov 2015 08:24:22 GMT
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Type: text/html
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Length: 192
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Via: 1.1 vegur
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Selected-Protocol: http/1.1
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Sent-Millis: 1446452662120
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Received-Millis: 1446452662316
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: <-- END HTTP
请帮忙,我卡住了,无法取得任何进展。
您正在此处嵌套多部分请求正文(多部分中的多部分)。
最近实现了类似的东西,而不是使用 @Multipart
和 @Part
你可以使用 @Body
和 MultipartBuilder
。
@POST("/api/photo/user/{userId}")
Call<Void> uploadUserProfilePhoto(@Path("userId") Integer userId, @Body RequestBody photo);
然后使用 MultipartBuilder.addFormDataPart(name, filename, requestBody)
而不是 MultipartBuilder.addPart(...)
private void uploadProfilePhoto() {
BeamItService service = BeamItServiceTransport.getService();
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpeg");
byte [] data = BitmapUtility.getBitmapToBytes(((BitmapDrawable) ivProfilePhoto.getDrawable()).getBitmap());
Log.d(TAG, String.format("Profile detals => user_id: %d, size of data: %d", 5, data.length));
RequestBody requestBody1 = RequestBody.create(MEDIA_TYPE_PNG, data);
Log.d(TAG, "requestBody: " + requestBody1.toString());
RequestBody requestBody2 = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("photo", "t.jpg", requestBody1)
.build();
Log.d(TAG, "requestBody: " + requestBody2.toString());
// ProfileDetails profileDetails = new DBHelper(this).fetchProfileDetails();
Call<Void> call = service.uploadUserProfilePhoto(5, requestBody2);
call.enqueue(new ProfilePhotoUploadCallback());
}
我正在使用 Square Retrofit 版本 2.0 beta2。我已尝试按照 this tutorial .我正在尝试将位图图像上传到服务器,但不知何故代码无法正常工作。我已经尝试使用 postman 测试我的服务器,我能够 post 照片甚至能够检索它。这是我的烧瓶控制器。
@app.route('/api/photo/user/<int:user_id>', methods=["POST"])
def post_user_photo(user_id):
app.logger.info("post_user_photo=> user_id:{}, photo: {}".format(
user_id,
request.files['photo'].filename,
))
user = User.query.get_or_404(user_id)
try:
user.photo = request.files['photo'].read()
except Exception as e:
app.logger.exception(e)
db.session.rollback()
raise
db.session.commit()
return "", codes.no_content
我已经使用 postman 来测试我的控制器,这里是 postman 生成的请求。
POST /api/photo/user/5 HTTP/1.1
Host: blooming-cliffs-9672.herokuapp.com
Cache-Control: no-cache
Postman-Token: 8117fb79-4781-449d-7d22-237c49b53389
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="photo"; filename="sfsu.jpg"
Content-Type: image/jpeg
----WebKitFormBoundary7MA4YWxkTrZu0gW
我已经定义了改造服务和上传图像,这是我的 Android 代码。接口部分
@Multipart
@POST("/api/photo/user/{userId}")
Call<Void> uploadUserProfilePhoto(@Path("userId") Integer userId, @Part("photo") RequestBody photo);
此处为客户端构建器部分
public static BeamItService getService(){
if (service == null) {
OkHttpClient client = new OkHttpClient();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
HttpLoggingInterceptor interceptor2 = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
client.interceptors().add(interceptor);
client.interceptors().add(interceptor2);
service = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build().create(BeamItService.class);
}
return service;
}
这里是 Android activity 尝试上传位图的代码。
private void uploadProfilePhoto(){
BeamItService service = BeamItServiceTransport.getService();
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpeg");
byte [] data = BitmapUtility.getBitmapToBytes(((BitmapDrawable) ivProfilePhoto.getDrawable()).getBitmap());
Log.d(TAG, String.format("Profile detals => user_id: %d, size of data: %d", 5, data.length));
RequestBody requestBody1 = RequestBody.create(MEDIA_TYPE_PNG,
data);
Log.d(TAG, "requestBody: " + requestBody1.toString());
RequestBody requestBody2 = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(Headers.of("Content-Disposition", "form-data; name=\"photo\"; filename=\"t.jpg\""),
requestBody1)
.build();
Log.d(TAG, "requestBody: " + requestBody2.toString());
// ProfileDetails profileDetails = new DBHelper(this).fetchProfileDetails();
Call<Void> call = service.uploadUserProfilePhoto(5, requestBody2);
call.enqueue(new ProfilePhotoUploadCallback());
}
private class ProfilePhotoUploadCallback implements Callback<Void> {
@Override
public void onResponse(Response<Void> response, Retrofit retrofit) {
Log.d(TAG, String.format("ProfilePhotoUploadCallback=> code: %d", response.code()));
}
@Override
public void onFailure(Throwable t) {
}
}
但是上传失败,flask app returns每次都是状态码400。我试图将断点放在烧瓶应用程序中,但请求甚至没有到达那里。 这是服务器日志
2015-11-02T06:05:42.288574+00:00 heroku[router]: at=info method=POST path="/api/photo/user/5" host=blooming-cliffs-9672.herokuapp.com request_id=2cc8b6c8-f12a-4e4b-8279-cedfc39712f2 fwd="204.28.113.240" dyno=web.1 connect=1ms service=88ms status=400 bytes=347
2015-11-02T06:05:42.209347+00:00 app[web.1]: [2015-11-02 06:05:42 +0000] [11] [DEBUG] POST /api/photo/user/5
我也尝试启用改造拦截器并记录请求和响应,但我没有得到整个 POST 请求正文。这是 Android 日志。
11-02 00:24:22.119 3904-4382/com.contactsharing.beamit D/OkHttp: --> POST /api/photo/user/5 HTTP/1.1
11-02 00:24:22.119 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Type: multipart/form-data; boundary=4031e177-0e4b-4f16-abe8-20c54e506846
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Length: 17171
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Host: blooming-cliffs-9672.herokuapp.com
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Connection: Keep-Alive
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Accept-Encoding: gzip
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: User-Agent: okhttp/2.6.0-SNAPSHOT
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: --> END POST
11-02 00:24:22.179 3904-4537/com.contactsharing.beamit I/DBHelper: Updated row: 1
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: <-- HTTP/1.1 400 BAD REQUEST (195ms)
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Connection: keep-alive
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Server: gunicorn/19.3.0
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Date: Mon, 02 Nov 2015 08:24:22 GMT
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Type: text/html
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Length: 192
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Via: 1.1 vegur
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Selected-Protocol: http/1.1
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Sent-Millis: 1446452662120
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Received-Millis: 1446452662316
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: <-- END HTTP
请帮忙,我卡住了,无法取得任何进展。
您正在此处嵌套多部分请求正文(多部分中的多部分)。
最近实现了类似的东西,而不是使用 @Multipart
和 @Part
你可以使用 @Body
和 MultipartBuilder
。
@POST("/api/photo/user/{userId}")
Call<Void> uploadUserProfilePhoto(@Path("userId") Integer userId, @Body RequestBody photo);
然后使用 MultipartBuilder.addFormDataPart(name, filename, requestBody)
MultipartBuilder.addPart(...)
private void uploadProfilePhoto() {
BeamItService service = BeamItServiceTransport.getService();
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpeg");
byte [] data = BitmapUtility.getBitmapToBytes(((BitmapDrawable) ivProfilePhoto.getDrawable()).getBitmap());
Log.d(TAG, String.format("Profile detals => user_id: %d, size of data: %d", 5, data.length));
RequestBody requestBody1 = RequestBody.create(MEDIA_TYPE_PNG, data);
Log.d(TAG, "requestBody: " + requestBody1.toString());
RequestBody requestBody2 = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("photo", "t.jpg", requestBody1)
.build();
Log.d(TAG, "requestBody: " + requestBody2.toString());
// ProfileDetails profileDetails = new DBHelper(this).fetchProfileDetails();
Call<Void> call = service.uploadUserProfilePhoto(5, requestBody2);
call.enqueue(new ProfilePhotoUploadCallback());
}