我尝试使用Retrofit2在服务器上发送文件。 我根据文档做了一切,但总是得到400服务器错误。
我试图这样做:
RequestBody body =
RequestBody.create(MediaType.parse("image/png"), photo);
//..........
@Multipart
@POST(ADD_PHOTO)
Observable<HPSPhotoResponse>
addPhoto(@Part("file") RequestBody file);
......并且像这样:
MultipartBody.Part part = MultipartBody.Part.createFormData("file", "file", body);
//...........
@Multipart
@POST(ADD_PHOTO)
Observable<HPSPhotoResponse>
addPhoto(@Part("file") MultipartBody.Part files);
无所谓。结果始终相同&#34;多部分请求:必需的MultipartFile参数&#39; file&#39;不存在&#34; - 服务器响应。
我认为服务器上的Spring工作不好但我在Swift(iOS)上做了相同的代码并且它有效!服务器在这里看到了这个文件&#39;一部分。
Alamofire.upload(method, endpoint, headers: headers,
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: self.filePath!, name: "file")
}
现在我希望它可以在Android上使用Retrofit。 但我甚至会查看Retrofit请求的日志,实际上我没有看到任何文件&#39;日志中的文字。
这有什么不对?
答案 0 :(得分:40)
您可以尝试以下示例代码。在此演示应用中,我们将从图库中选择后上传照片。希望它有所帮助!
build.gradle 文件:
dependencies {
...
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
...
}
WebAPIService.java 文件:
public interface WebAPIService {
@Multipart
@POST("/api/fileupload")
Call<ResponseBody> postFile(@Part MultipartBody.Part file, @Part("description") RequestBody description);
}
FileActivity.java 文件:
...
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class FileActivity extends AppCompatActivity {
private final Context mContext = this;
private final String API_URL_BASE = "http://serverip:port";
private final String LOG_TAG = "BNK";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file);
selectImage(); // selects a photo from Gallery
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK && requestCode == 100) {
Uri fileUri = data.getData();
if (fileUri != null) {
uploadFile(fileUri); // uploads the file to the web service
}
}
}
private void uploadFile(Uri fileUri) {
String filePath = getRealPathFromUri(fileUri);
if (filePath != null && !filePath.isEmpty()) {
File file = new File(filePath);
if (file.exists()) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL_BASE)
.build();
WebAPIService service = retrofit.create(WebAPIService.class);
// creates RequestBody instance from file
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
// MultipartBody.Part is used to send also the actual filename
MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
// adds another part within the multipart request
String descriptionString = "Sample description";
RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
// executes the request
Call<ResponseBody> call = service.postFile(body, description);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call,
Response<ResponseBody> response) {
Log.i(LOG_TAG, "success");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(LOG_TAG, t.getMessage());
}
});
}
}
}
private void selectImage() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, 100);
}
public String getRealPathFromUri(final Uri uri) {
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(mContext, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(mContext, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(mContext, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(mContext, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
private String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
private boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
private boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
private boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
}
答案 1 :(得分:1)
在我的情况下,服务器没有处理一些改装正在发送的标头。这就是为什么我不得不从改装请求中删除无用的标头。我已经创建了这样的接口函数:
@Multipart
@POST("my/files/photo/")
Call<FileUploadResponse> uploadPhoto(@Header("Content-Type") String contentType,
@Header("Authorization") String auth,
@Part MultipartBody body);
并称之为:
ApiClient.ApiInterface client = ApiClient.getClient();
File file = new File(getPathFromUri(fileUri));
RequestBody fileBody = RequestBody.create(MediaType.parse(getContentResolver().getType(fileUri)), file);
MultipartBody body = new MultipartBody.Builder().addFormDataPart("file-type", "profile")
.addFormDataPart("photo", "image.png", fileBody)
.build();
client.uploadPhoto("multipart/form-data; boundary=" + body.boundary(),
PrefManager.getInstance().getToken(), body);
请在此处查看详细信息:Upload picture to server using retrofit 2