java - servidor - ¿Cómo usar okhttp para subir un archivo?
subir archivos con spring mvc (5)
Yo uso okhttp para ser mi cliente http. Creo que es una buena API, pero el documento no es tan detallado.
¿Cómo usarlo para hacer una solicitud de publicación http con carga de archivos?
public Multipart createMultiPart(File file){
Part part = (Part) new Part.Builder().contentType("").body(new File("1.png")).build();
//how to set part name?
Multipart m = new Multipart.Builder().addPart(part).build();
return m;
}
public String postWithFiles(String url,Multipart m) throws IOException{
ByteArrayOutputStream out = new ByteArrayOutputStream();
m.writeBodyTo(out)
;
Request.Body body = Request.Body.create(MediaType.parse("application/x-www-form-urlencoded"),
out.toByteArray());
Request req = new Request.Builder().url(url).post(body).build();
return client.newCall(req).execute().body().string();
}
mi pregunta es:
- cómo establecer el nombre de la parte? en el formulario, el archivo debe llamarse archivo1.
- ¿Cómo agregar otros campos en el formulario?
Aquí hay una función básica que usa okhttp para cargar un archivo y un campo arbitrario (simula literalmente un envío de formulario HTML normal)
Cambie el tipo de mime para que coincida con su archivo (aquí asumo .csv) o conviértalo en un parámetro de la función si va a cargar diferentes tipos de archivos
public static Boolean uploadFile(String serverURL, File file) {
try {
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("text/csv"), file))
.addFormDataPart("some-field", "some-value")
.build();
Request request = new Request.Builder()
.url(serverURL)
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
// Handle the error
}
@Override
public void onResponse(Response response) throws IOException {
if (!response.isSuccessful()) {
// Handle the error
}
// Upload successful
}
});
return true;
} catch (Exception ex) {
// Handle the error
}
return false;
}
Nota : debido a que es una llamada asíncrona, el tipo de retorno booleano no indica una carga exitosa, pero solo que la solicitud se envió a la cola okhttp.
Aquí hay una respuesta que funciona con OkHttp 3.2.0:
public void upload(String url, File file) throws IOException {
RequestBody formBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("text/plain"), file))
.addFormDataPart("other_field", "other_field_value")
.build();
Request request = new Request.Builder().url(url).post(formBody).build();
Response response = this.client.newCall(request).execute();
}
He creado una clase de ayuda genial para OkHttp3
. aquí
public class OkHttp3Helper {
public static final String TAG;
private static final okhttp3.OkHttpClient client;
static {
TAG = OkHttp3Helper.class.getSimpleName();
client = new okhttp3.OkHttpClient.Builder()
.readTimeout(7, TimeUnit.MINUTES)
.writeTimeout(7, TimeUnit.MINUTES)
.build();
}
private Context context;
public OkHttp3Helper(Context context) {
this.context = context;
}
/**
* <strong>Uses:</strong><br/>
* <p>
* {@code
* ArrayMap<String, String> formField = new ArrayMap<>();}
* <br/>
* {@code formField.put("key1", "value1");}<br/>
* {@code formField.put("key2", "value2");}<br/>
* {@code formField.put("key3", "value3");}<br/>
* <br/>
* {@code String response = helper.postToServer("http://www.example.com/", formField);}<br/>
* </p>
*
* @param url String
* @param formField android.support.v4.util.ArrayMap
* @return response from server in String format
* @throws Exception
*/
@NonNull
public String postToServer(@NonNull String url, @Nullable ArrayMap<String, String> formField)
throws Exception {
okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder().url(url);
if (formField != null) {
okhttp3.FormBody.Builder formBodyBuilder = new okhttp3.FormBody.Builder();
for (Map.Entry<String, String> entry : formField.entrySet()) {
formBodyBuilder.add(entry.getKey(), entry.getValue());
}
requestBuilder.post(formBodyBuilder.build());
}
okhttp3.Request request = requestBuilder.build();
okhttp3.Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException(response.message());
}
return response.body().string();
}
/**
* <strong>Uses:</strong><br/>
* <p>
* {@code
* ArrayMap<String, String> formField = new ArrayMap<>();}
* <br/>
* {@code formField.put("key1", "value1");}<br/>
* {@code formField.put("key2", "value2");}<br/>
* {@code formField.put("key3", "value3");}<br/>
* <br/>
* {@code
* ArrayMap<String, File> filePart = new ArrayMap<>();}
* <br/>
* {@code filePart.put("key1", new File("pathname"));}<br/>
* {@code filePart.put("key2", new File("pathname"));}<br/>
* {@code filePart.put("key3", new File("pathname"));}<br/>
* <br/>
* {@code String response = helper.postToServer("http://www.example.com/", formField, filePart);}<br/>
* </p>
*
* @param url String
* @param formField android.support.v4.util.ArrayMap
* @param filePart android.support.v4.util.ArrayMap
* @return response from server in String format
* @throws Exception
*/
@NonNull
public String postMultiPartToServer(@NonNull String url,
@Nullable ArrayMap<String, String> formField,
@Nullable ArrayMap<String, File> filePart)
throws Exception {
okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder().url(url);
if (formField != null || filePart != null) {
okhttp3.MultipartBody.Builder multipartBodyBuilder = new okhttp3.MultipartBody.Builder();
multipartBodyBuilder.setType(okhttp3.MultipartBody.FORM);
if (formField != null) {
for (Map.Entry<String, String> entry : formField.entrySet()) {
multipartBodyBuilder.addFormDataPart(entry.getKey(), entry.getValue());
}
}
if (filePart != null) {
for (Map.Entry<String, File> entry : filePart.entrySet()) {
File file = entry.getValue();
multipartBodyBuilder.addFormDataPart(
entry.getKey(),
file.getName(),
okhttp3.RequestBody.create(getMediaType(file.toURI()), file)
);
}
}
requestBuilder.post(multipartBodyBuilder.build());
}
okhttp3.Request request = requestBuilder.build();
okhttp3.Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException(response.message());
}
return response.body().string();
}
private okhttp3.MediaType getMediaType(URI uri1) {
Uri uri = Uri.parse(uri1.toString());
String mimeType;
if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
ContentResolver cr = context.getContentResolver();
mimeType = cr.getType(uri);
} else {
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
.toString());
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
fileExtension.toLowerCase());
}
return okhttp3.MediaType.parse(mimeType);
}
}
Nota: esta respuesta es para okhttp 1.x / 2.x. Para 3.x, vea esta otra respuesta .
La clase Multipart
de mimecraft encapsula todo el cuerpo de HTTP y puede manejar campos regulares de la siguiente manera:
Multipart m = new Multipart.Builder()
.type(Multipart.Type.FORM)
.addPart(new Part.Builder()
.body("value")
.contentDisposition("form-data; name=/"non_file_field/"")
.build())
.addPart(new Part.Builder()
.contentType("text/csv")
.body(aFile)
.contentDisposition("form-data; name=/"file_field/"; filename=/"file1/"")
.build())
.build();
Eche un vistazo a los ejemplos de codificación multiparte / datos de formulario para tener una idea de cómo necesita construir las partes.
Una vez que tenga un objeto Multipart
, todo lo que queda por hacer es especificar el encabezado de Content-Type
correcto y pasar los bytes del cuerpo a la solicitud.
Ya que parece que estás trabajando con la v2.0 de la API de OkHttp, con la que no tengo experiencia, esto es solo un código:
// You''ll probably need to change the MediaType to use the Content-Type
// from the multipart object
Request.Body body = Request.Body.create(
MediaType.parse(m.getHeaders().get("Content-Type")),
out.toByteArray());
Para OkHttp 1.5.4, aquí hay un código simplificado que estoy usando y que está adaptado de un fragmento de muestra :
OkHttpClient client = new OkHttpClient();
OutputStream out = null;
try {
URL url = new URL("http://www.example.com");
HttpURLConnection connection = client.open(url);
for (Map.Entry<String, String> entry : multipart.getHeaders().entrySet()) {
connection.addRequestProperty(entry.getKey(), entry.getValue());
}
connection.setRequestMethod("POST");
// Write the request.
out = connection.getOutputStream();
multipart.writeBodyTo(out);
out.close();
// Read the response.
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException("Unexpected HTTP response: "
+ connection.getResponseCode() + " " + connection.getResponseMessage());
}
} finally {
// Clean up.
try {
if (out != null) out.close();
} catch (Exception e) {
}
}
OkHttpClient client = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).writeTimeout(180, TimeUnit.SECONDS).readTimeout(180, TimeUnit.SECONDS).build();
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("File", path.getName(),RequestBody.create(MediaType.parse("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),path))
.addFormDataPart("username", username)
.addFormDataPart("password", password)
.build();
Request request = new Request.Builder().url(url).post(body).build();
Response response = client.newCall(request).execute();
result = response.body().string();
El código anterior enviará el nombre de usuario, la contraseña como parámetro de publicación y el archivo se cargará con el nombre de "Archivo".
PHP Server recibirá los archivos
if (isset($_FILES["File"]) &&
isset($_POST[''username'']) &&
isset($_POST[''password''])) {
//All Values found
}else{
echo ''please send the required data'';
}