android http multipartform-data android-sdk-2.1

Publicar solicitud multiparte con Android SDK



http multipartform-data (11)

Aquí está la solución LIGHT WEIGHTED que funcionó para mí sin HTTPCore externo y tales libs. Me enfrentaba al problema de los métodos de 64 K, por lo que no me queda otra opción para evitar las bibliotecas HTTPCore

import java.util.List; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; /** * This utility class provides an abstraction layer for sending multipart HTTP * POST requests to a web server. * * @author www.codejava.net */ public class MultipartUtility { private final String boundary; private static final String LINE_FEED = "/r/n"; private HttpURLConnection httpConn; private String charset; private OutputStream outputStream; private PrintWriter writer; /** * This constructor initializes a new HTTP POST request with content type * is set to multipart/form-data * * @param requestURL * @param charset * @throws IOException */ public MultipartUtility(String requestURL, String charset) throws IOException { this.charset = charset; // creates a unique boundary based on time stamp boundary = "===" + System.currentTimeMillis() + "==="; URL url = new URL(requestURL); httpConn = (HttpURLConnection) url.openConnection(); httpConn.setUseCaches(false); httpConn.setDoOutput(true); // indicates POST method httpConn.setDoInput(true); httpConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); httpConn.setRequestProperty("User-Agent", "CodeJava Agent"); httpConn.setRequestProperty("Test", "Bonjour"); outputStream = httpConn.getOutputStream(); writer = new PrintWriter(new OutputStreamWriter(outputStream, charset), true); } /** * Adds a form field to the request * * @param name field name * @param value field value */ public void addFormField(String name, String value) { writer.append("--" + boundary).append(LINE_FEED); writer.append("Content-Disposition: form-data; name=/"" + name + "/"") .append(LINE_FEED); writer.append("Content-Type: text/plain; charset=" + charset).append( LINE_FEED); writer.append(LINE_FEED); writer.append(value).append(LINE_FEED); writer.flush(); } /** * Adds a upload file section to the request * * @param fieldName name attribute in <input type="file" name="..." /> * @param uploadFile a File to be uploaded * @throws IOException */ public void addFilePart(String fieldName, File uploadFile) throws IOException { String fileName = uploadFile.getName(); writer.append("--" + boundary).append(LINE_FEED); writer.append( "Content-Disposition: form-data; name=/"" + fieldName + "/"; filename=/"" + fileName + "/"") .append(LINE_FEED); writer.append( "Content-Type: " + URLConnection.guessContentTypeFromName(fileName)) .append(LINE_FEED); writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED); writer.append(LINE_FEED); writer.flush(); FileInputStream inputStream = new FileInputStream(uploadFile); byte[] buffer = new byte[4096]; int bytesRead = -1; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.flush(); inputStream.close(); writer.append(LINE_FEED); writer.flush(); } /** * Adds a header field to the request. * * @param name - name of the header field * @param value - value of the header field */ public void addHeaderField(String name, String value) { writer.append(name + ": " + value).append(LINE_FEED); writer.flush(); } /** * Completes the request and receives response from the server. * * @return a list of Strings as response in case the server returned * status OK, otherwise an exception is thrown. * @throws IOException */ public List<String> finish() throws IOException { List<String> response = new ArrayList<String>(); writer.append(LINE_FEED).flush(); writer.append("--" + boundary + "--").append(LINE_FEED); writer.close(); // checks server''s status code first int status = httpConn.getResponseCode(); if (status == HttpURLConnection.HTTP_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader( httpConn.getInputStream())); String line = null; while ((line = reader.readLine()) != null) { response.add(line); } reader.close(); httpConn.disconnect(); } else { throw new IOException("Server returned non-OK status: " + status); } return response; } }

USO

private void uploadMedia() { try { String charset = "UTF-8"; File uploadFile1 = new File("/sdcard/myvideo.mp4"); String requestURL = Data.BASE_URL+Data.URL_UPLOAD_REACTION_TEST; MultipartUtility multipart = new MultipartUtility(requestURL, charset); // multipart.addHeaderField("User-Agent", "CodeJava"); // multipart.addHeaderField("Test-Header", "Header-Value"); multipart.addFormField("friend_id", "Cool Pictures"); multipart.addFormField("userid", "Java,upload,Spring"); multipart.addFilePart("uploadedfile", uploadFile1); List<String> response = multipart.finish(); Log.v("rht", "SERVER REPLIED:"); for (String line : response) { Log.v("rht", "Line : "+line); } } catch (Exception e) { e.printStackTrace(); } }

Código PHP para aceptar la carga

<?php $friend_id = $_REQUEST[''friend_id'']; $userid = $_REQUEST[''userid'']; echo ''friend_id : ''.$friend_id. '' userid ''.$userid; move_uploaded_file($_FILES[''uploadedfile''][''tmp_name''], "./uploads/".$_FILES["uploadedfile"]["name"]); ?>

Estoy tratando de hacer algo que pensé que sería relativamente simple: subir una imagen a un servidor con el SDK de Android. Me encontraron un montón de código de ejemplo:

http://groups.google.com/group/android-developers/browse_thread/thread/f9e17bbaf50c5fc/46145fcacd450e48

http://linklens.blogspot.com/2009/06/android-multipart-upload.html

Pero ninguno funciona para mí. La confusión que sigo encontrando es lo que realmente se necesita para hacer una solicitud múltiple. ¿Cuál es la forma más simple de tener una carga múltiple (con una imagen) para Android?

¡Cualquier ayuda o consejo sería muy apreciado!


Aquí hay un enfoque simple si está utilizando la biblioteca AOSP Volley .

Extienda la clase Request<T> siguiente manera-

public class MultipartRequest extends Request<String> { private static final String FILE_PART_NAME = "file"; private final Response.Listener<String> mListener; private final Map<String, File> mFilePart; private final Map<String, String> mStringPart; MultipartEntityBuilder entity = MultipartEntityBuilder.create(); HttpEntity httpentity; public MultipartRequest(String url, Response.ErrorListener errorListener, Response.Listener<String> listener, Map<String, File> file, Map<String, String> mStringPart) { super(Method.POST, url, errorListener); mListener = listener; mFilePart = file; this.mStringPart = mStringPart; entity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); buildMultipartEntity(); } public void addStringBody(String param, String value) { mStringPart.put(param, value); } private void buildMultipartEntity() { for (Map.Entry<String, File> entry : mFilePart.entrySet()) { // entity.addPart(entry.getKey(), new FileBody(entry.getValue(), ContentType.create("image/jpeg"), entry.getKey())); try { entity.addBinaryBody(entry.getKey(), Utils.toByteArray(new FileInputStream(entry.getValue())), ContentType.create("image/jpeg"), entry.getKey() + ".JPG"); } catch (FileNotFoundException e) { e.printStackTrace(); } } for (Map.Entry<String, String> entry : mStringPart.entrySet()) { if (entry.getKey() != null && entry.getValue() != null) { entity.addTextBody(entry.getKey(), entry.getValue()); } } } @Override public String getBodyContentType() { return httpentity.getContentType().getValue(); } @Override public byte[] getBody() throws AuthFailureError { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { httpentity = entity.build(); httpentity.writeTo(bos); } catch (IOException e) { VolleyLog.e("IOException writing to ByteArrayOutputStream"); } return bos.toByteArray(); } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { Log.d("Response", new String(response.data)); return Response.success(new String(response.data), getCacheEntry()); } @Override protected void deliverResponse(String response) { mListener.onResponse(response); } }

Puede crear y agregar una solicitud como-

Map<String, String> params = new HashMap<>(); params.put("name", name.getText().toString()); params.put("email", email.getText().toString()); params.put("user_id", appPreferences.getInt( Utils.PROPERTY_USER_ID, -1) + ""); params.put("password", password.getText().toString()); params.put("imageName", pictureName); Map<String, File> files = new HashMap<>(); files.put("photo", new File(Utils.LOCAL_RESOURCE_PATH + pictureName)); MultipartRequest multipartRequest = new MultipartRequest(Utils.BASE_URL + "editprofile/" + appPreferences.getInt(Utils.PROPERTY_USER_ID, -1), new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // TODO Auto-generated method stub Log.d("Error: ", error.toString()); FugaDialog.showErrorDialog(ProfileActivity.this); } }, new Response.Listener<String>() { @Override public void onResponse(String jsonResponse) { JSONObject response = null; try { Log.d("jsonResponse: ", jsonResponse); response = new JSONObject(jsonResponse); } catch (JSONException e) { e.printStackTrace(); } try { if (response != null && response.has("statusmessage") && response.getBoolean("statusmessage")) { updateLocalRecord(); } } catch (JSONException e) { e.printStackTrace(); } FugaDialog.dismiss(); } }, files, params); RequestQueue queue = Volley.newRequestQueue(this); queue.add(multipartRequest);


Como MultiPartEntity está en desuso . ¡Así que aquí está la nueva forma de hacerlo! Y solo necesita httpcore.jar(latest) y httpmime.jar(latest) descargarlos del sitio de Apache.

try { HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost(URL); MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create(); entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); entityBuilder.addTextBody(USER_ID, userId); entityBuilder.addTextBody(NAME, name); entityBuilder.addTextBody(TYPE, type); entityBuilder.addTextBody(COMMENT, comment); entityBuilder.addTextBody(LATITUDE, String.valueOf(User.Latitude)); entityBuilder.addTextBody(LONGITUDE, String.valueOf(User.Longitude)); if(file != null) { entityBuilder.addBinaryBody(IMAGE, file); } HttpEntity entity = entityBuilder.build(); post.setEntity(entity); HttpResponse response = client.execute(post); HttpEntity httpEntity = response.getEntity(); result = EntityUtils.toString(httpEntity); Log.v("result", result); } catch(Exception e) { e.printStackTrace(); }


Elimine toda su httpclient, dependencia de httpmime y agregue esta compile ''commons-httpclient:commons-httpclient:3.1'' dependencia compile ''commons-httpclient:commons-httpclient:3.1'' . Esta dependencia ha incorporado MultipartRequestEntity para que pueda cargar fácilmente uno o más archivos en el servidor

public class FileUploadUrlConnection extends AsyncTask<String, String, String> { private Context context; private String url; private List<File> files; public FileUploadUrlConnection(Context context, String url, List<File> files) { this.context = context; this.url = url; this.files = files; } @Override protected String doInBackground(String... params) { HttpClient client = new HttpClient(); PostMethod post = new PostMethod(url); HttpClientParams connectionParams = new HttpClientParams(); post.setRequestHeader(// Your header goes here ); try { Part[] parts = new Part[files.size()]; for (int i=0; i<files.size(); i++) { Part part = new FilePart(files.get(i).getName(), files.get(i)); parts[i] = part; } MultipartRequestEntity entity = new MultipartRequestEntity(parts, connectionParams); post.setRequestEntity(entity); int statusCode = client.executeMethod(post); String response = post.getResponseBodyAsString(); Log.v("Multipart "," "+response); if(statusCode == 200) { return response; } } catch (IOException e) { e.printStackTrace(); } return null; }

También puede agregar el tiempo de espera de solicitud y respuesta

client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000); client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000);



Para la posteridad, no vi a okhttp mencionado. Publicación relacionada.

Básicamente construyes el cuerpo usando un MultipartBody.Builder, y luego publicas esto en una solicitud.

Ejemplo en kotlin:

val body = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( "file", file.getName(), RequestBody.create(MediaType.parse("image/png"), file) ) .addFormDataPart("timestamp", Date().time.toString()) .build() val request = Request.Builder() .url(url) .post(body) .build() httpClient.newCall(request).enqueue(object : okhttp3.Callback { override fun onFailure(call: Call?, e: IOException?) { ... } override fun onResponse(call: Call?, response: Response?) { ... } })


Prueba esto:

public void SendMultipartFile() { Log.d(TAG, "UPLOAD: SendMultipartFile"); DefaultHttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost( <url> ); File file = new File("/sdcard/spider.jpg"); Log.d(TAG, "UPLOAD: setting up multipart entity"); MultipartEntity mpEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); Log.d(TAG, "UPLOAD: file length = " + file.length()); Log.d(TAG, "UPLOAD: file exist = " + file.exists()); try { mpEntity.addPart("datafile", new FileBody(file, "application/octet")); mpEntity.addPart("id", new StringBody("1")); } catch (UnsupportedEncodingException e1) { Log.d(TAG, "UPLOAD: UnsupportedEncodingException"); e1.printStackTrace(); } httppost.setEntity(mpEntity); Log.d(TAG, "UPLOAD: executing request: " + httppost.getRequestLine()); Log.d(TAG, "UPLOAD: request: " + httppost.getEntity().getContentType().toString()); HttpResponse response; try { Log.d(TAG, "UPLOAD: about to execute"); response = httpclient.execute(httppost); Log.d(TAG, "UPLOAD: executed"); HttpEntity resEntity = response.getEntity(); Log.d(TAG, "UPLOAD: respose code: " + response.getStatusLine().toString()); if (resEntity != null) { Log.d(TAG, "UPLOAD: " + EntityUtils.toString(resEntity)); } if (resEntity != null) { resEntity.consumeContent(); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }


Puedo recomendar la biblioteca Ion, use 3 dependencias y puede encontrar los tres archivos jar en estos dos sitios:
https://github.com/koush/ion#jars (ion y androidasync)

https://code.google.com/p/google-gson/downloads/list (gson)

try { Ion.with(this, "http://www.urlthatyouwant.com/post/page") .setMultipartParameter("field1", "This is field number 1") .setMultipartParameter("field2", "Field 2 is shorter") .setMultipartFile("imagefile", new File(Environment.getExternalStorageDirectory()+"/testfile.jpg")) .asString() .setCallback(new FutureCallback<String>() { @Override public void onCompleted(Exception e, String result) { System.out.println(result); }}); } catch(Exception e) { // Do something about exceptions System.out.println("exception: " + e); }

esto se ejecutará de manera asíncrona y la devolución de llamada se ejecutará en el hilo de la interfaz de usuario una vez que se reciba una respuesta. Recomiendo encarecidamente que vaya a https://github.com/koush/ion para obtener más información.


Recomiendo Loopj.

Lo he utilizado con éxito para cargar varios archivos a la vez, incluidos diferentes tipos de mime. Simplemente haz esto:

File myVideo = new File("/path/to/myvideo.mp4"); File myPic = new File("/path/to/mypic.jpg"); RequestParams params = new RequestParams(); try { params.put("profile_picture", myPic); params.put("my_video", myVideo); } catch(FileNotFoundException e) {}

Para archivos grandes o muchos, puede que tenga que aumentar el tiempo de espera, de lo contrario se utiliza el tiempo de espera predeterminado, que puede ser demasiado corto:

client.setTimeout(500000) //make this the appropriate timeout in milliseconds

Por favor, consulte estos enlaces para obtener una descripción completa de loopj y cómo usarlo, de lejos la biblioteca http async más fácil que he encontrado:

http://loopj.com/android-async-http/ http://loopj.com/android-async-http/doc/com/loopj/android/http/AsyncHttpClient.html


Actualización 29 de abril de 2014:

Mi respuesta es un poco vieja y supongo que preferiría usar algún tipo de biblioteca de alto nivel como Retrofit .

Basado en este blog, se me ocurrió la siguiente solución: http://blog.tacticalnuclearstrike.com/2010/01/using-multipartentity-in-android-applications/

¡Tendrás que descargar bibliotecas adicionales para ejecutar MultipartEntity !

1) Descargue httpcomponents-client-4.1.zip desde http://james.apache.org/download.cgi#Apache_Mime4J y agregue apache-mime4j-0.6.1.jar a su proyecto.

2) Descargue httpcomponents-client-4.1-bin.zip desde http://hc.apache.org/downloads.cgi y agregue httpclient-4.1.jar, httpcore-4.1.jar y httpmime-4.1.jar a su proyecto.

3) Usa el siguiente código de ejemplo.

private DefaultHttpClient mHttpClient; public ServerCommunication() { HttpParams params = new BasicHttpParams(); params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); mHttpClient = new DefaultHttpClient(params); } public void uploadUserPhoto(File image) { try { HttpPost httppost = new HttpPost("some url"); MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); multipartEntity.addPart("Title", new StringBody("Title")); multipartEntity.addPart("Nick", new StringBody("Nick")); multipartEntity.addPart("Email", new StringBody("Email")); multipartEntity.addPart("Description", new StringBody(Settings.SHARE.TEXT)); multipartEntity.addPart("Image", new FileBody(image)); httppost.setEntity(multipartEntity); mHttpClient.execute(httppost, new PhotoUploadResponseHandler()); } catch (Exception e) { Log.e(ServerCommunication.class.getName(), e.getLocalizedMessage(), e); } } private class PhotoUploadResponseHandler implements ResponseHandler<Object> { @Override public Object handleResponse(HttpResponse response) throws ClientProtocolException, IOException { HttpEntity r_entity = response.getEntity(); String responseString = EntityUtils.toString(r_entity); Log.d("UPLOAD", responseString); return null; } }


public class Multipart{ private final Map<String, String> headrs; private String url; private HttpURLConnection con; private OutputStream os; private String delimiter = "--"; private String boundary = "TRR" + Long.toString(System.currentTimeMillis()) + "TRR"; public Multipart (String url, Map<String, String> headers) { this.url = url; this.headrs = headers; } public void connectForMultipart() throws Exception { con = (HttpURLConnection) (new URL(url)).openConnection(); con.setRequestMethod("POST"); con.setDoInput(true); con.setDoOutput(true); con.setRequestProperty("Connection", "Keep-Alive"); for (Map.Entry<String, String> entry : headrs.entrySet()) { con.setRequestProperty(entry.getKey(), entry.getValue()); } con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); con.connect(); os = con.getOutputStream(); } public void addFormPart(String paramName, String value) throws Exception { writeParamData(paramName, value); } public void addFilePart(String paramName, String fileName, byte[] data) throws Exception { os.write((delimiter + boundary + "/r/n").getBytes()); os.write(("Content-Disposition: form-data; name=/"" + paramName + "/"; filename=/"" + fileName + "/"/r/n").getBytes()); os.write(("Content-Type: application/octet-stream/r/n").getBytes()); os.write(("Content-Transfer-Encoding: binary/r/n").getBytes()); os.write("/r/n".getBytes()); os.write(data); os.write("/r/n".getBytes()); } public void finishMultipart() throws Exception { os.write((delimiter + boundary + delimiter + "/r/n").getBytes()); } public String getResponse() throws Exception { InputStream is = con.getInputStream(); byte[] b1 = new byte[1024]; StringBuffer buffer = new StringBuffer(); while (is.read(b1) != -1) buffer.append(new String(b1)); con.disconnect(); return buffer.toString(); } private void writeParamData(String paramName, String value) throws Exception { os.write((delimiter + boundary + "/r/n").getBytes()); os.write("Content-Type: text/plain/r/n".getBytes());//;charset=utf-8 os.write(("Content-Disposition: form-data; name=/"" + paramName + "/"/r/n").getBytes()); ; os.write(("/r/n" + value + "/r/n").getBytes()); } }

Luego llama abajo

Multipart multipart = new Multipart(url__, map); multipart .connectForMultipart(); multipart .addFormPart(entry.getKey(), entry.getValue()); multipart .addFilePart(KeyName, "FileName", imagedata); multipart .finishMultipart();