¿Cómo enviar una solicitud POST en JSON usando HTTPClient en Android?

111

Estoy tratando de descubrir cómo PUBLICAR JSON desde Android usando HTTPClient. He estado tratando de resolver esto por un tiempo, he encontrado muchos ejemplos en línea, pero no puedo hacer que ninguno funcione. Creo que esto se debe a mi falta de conocimiento de JSON / redes en general. Sé que hay muchos ejemplos, pero ¿alguien podría indicarme un tutorial real? Estoy buscando un proceso paso a paso con código y una explicación de por qué hace cada paso, o de lo que hace ese paso. No es necesario que sea complicado, será suficiente.

Una vez más, sé que hay un montón de ejemplos por ahí, realmente estoy buscando un ejemplo con una explicación de lo que está sucediendo exactamente y por qué está sucediendo de esa manera.

Si alguien conoce un buen libro de Android sobre esto, hágamelo saber.

Gracias nuevamente por la ayuda @terrance, aquí está el código que describí a continuación

public void shNameVerParams() throws Exception{
     String path = //removed
     HashMap  params = new HashMap();

     params.put(new String("Name"), "Value"); 
     params.put(new String("Name"), "Value");

     try {
        HttpClient.SendHttpPost(path, params);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
 }
Gaurav Gandhi
fuente
¿Quizás pueda publicar uno de los ejemplos que no puede hacer funcionar? Al hacer que algo funcione, aprenderá cómo encajan las piezas.
Fredw

Respuestas:

157

En esta respuesta, estoy usando un ejemplo publicado por Justin Grammens .

Sobre JSON

JSON son las siglas de JavaScript Object Notation. En JavaScript, las propiedades pueden ser referenciadas tanto así object1.namecomo así object['name'];. El ejemplo del artículo usa este bit de JSON.

El
objeto de ventilador Parts A con el correo electrónico como clave y [email protected] como valor

{
  fan:
    {
      email : '[email protected]'
    }
}

Entonces, el objeto equivalente sería fan.email;o fan['email'];. Ambos tendrían el mismo valor de '[email protected]'.

Acerca de la solicitud de HttpClient

Lo siguiente es lo que usó nuestro autor para realizar una solicitud HttpClient . No pretendo ser un experto en todo esto, así que si alguien tiene una mejor manera de expresar algo de la terminología, no dude en hacerlo.

public static HttpResponse makeRequest(String path, Map params) throws Exception 
{
    //instantiates httpclient to make request
    DefaultHttpClient httpclient = new DefaultHttpClient();

    //url with the post data
    HttpPost httpost = new HttpPost(path);

    //convert parameters into JSON object
    JSONObject holder = getJsonObjectFromMap(params);

    //passes the results to a string builder/entity
    StringEntity se = new StringEntity(holder.toString());

    //sets the post request as the resulting string
    httpost.setEntity(se);
    //sets a request header so the page receving the request
    //will know what to do with it
    httpost.setHeader("Accept", "application/json");
    httpost.setHeader("Content-type", "application/json");

    //Handles what is returned from the page 
    ResponseHandler responseHandler = new BasicResponseHandler();
    return httpclient.execute(httpost, responseHandler);
}

Mapa

Si no está familiarizado con la Mapestructura de datos, consulte la referencia de Java Map . En resumen, un mapa es similar a un diccionario o un hash.

private static JSONObject getJsonObjectFromMap(Map params) throws JSONException {

    //all the passed parameters from the post request
    //iterator used to loop through all the parameters
    //passed in the post request
    Iterator iter = params.entrySet().iterator();

    //Stores JSON
    JSONObject holder = new JSONObject();

    //using the earlier example your first entry would get email
    //and the inner while would get the value which would be '[email protected]' 
    //{ fan: { email : '[email protected]' } }

    //While there is another entry
    while (iter.hasNext()) 
    {
        //gets an entry in the params
        Map.Entry pairs = (Map.Entry)iter.next();

        //creates a key for Map
        String key = (String)pairs.getKey();

        //Create a new map
        Map m = (Map)pairs.getValue();   

        //object for storing Json
        JSONObject data = new JSONObject();

        //gets the value
        Iterator iter2 = m.entrySet().iterator();
        while (iter2.hasNext()) 
        {
            Map.Entry pairs2 = (Map.Entry)iter2.next();
            data.put((String)pairs2.getKey(), (String)pairs2.getValue());
        }

        //puts email and '[email protected]'  together in map
        holder.put(key, data);
    }
    return holder;
}

Siéntase libre de comentar cualquier pregunta que surja sobre esta publicación o si no he dejado algo claro o si no he tocado algo sobre lo que todavía está confundido ... etc., lo que sea que realmente se le ocurra.

(Eliminaré si Justin Grammens no lo aprueba. Pero si no, gracias a Justin por ser genial al respecto).

Actualizar

Acabo de recibir un comentario sobre cómo usar el código y me di cuenta de que había un error en el tipo de devolución. La firma del método se configuró para devolver una cadena, pero en este caso no devolvía nada. Cambié la firma a HttpResponse y lo referiré a este enlace sobre Cómo obtener el cuerpo de respuesta de HttpResponse, la variable de ruta es la URL y la actualicé para corregir un error en el código.

Terrance
fuente
Gracias @Terrance. Entonces, en una clase diferente, está creando un mapa que tiene diferentes claves y valores que luego se convertirán en JSONObjects. Intenté implementar algo similar, pero tampoco tengo experiencia con mapas, agregaré el código de lo que intenté implementar en mi publicación original. Sus explicaciones de lo que estaba sucediendo se hicieron desde entonces, y logré que funcionara creando JSONObjects con nombres y valores codificados. ¡Gracias!
Woot, me alegro de haber podido ayudar.
Terrance
Justin dice que lo aprueba. Debería tener suficiente reputación para venir y dejar un comentario él mismo a estas alturas.
Abizern
Quiero usar este código. ¿Cómo hago con esto? Especifique cuál es la variable de ruta y qué debe devolverse para que en mi extremo de Java pueda recuperar los datos.
Prateek
3
No hay ninguna razón para getJsonObjectFromMap(): JSONObject tiene un constructor que toma Map: developer.android.com/reference/org/json/…
pr1001
41

Aquí hay una solución alternativa a la respuesta de @ Terrance. Puede subcontratar fácilmente la conversión. La biblioteca Gson hace un trabajo maravilloso al convertir varias estructuras de datos en JSON y al revés.

public static void execute() {
    Map<String, String> comment = new HashMap<String, String>();
    comment.put("subject", "Using the GSON library");
    comment.put("message", "Using libraries is convenient.");
    String json = new GsonBuilder().create().toJson(comment, Map.class);
    makeRequest("http://192.168.0.1:3000/post/77/comments", json);
}

public static HttpResponse makeRequest(String uri, String json) {
    try {
        HttpPost httpPost = new HttpPost(uri);
        httpPost.setEntity(new StringEntity(json));
        httpPost.setHeader("Accept", "application/json");
        httpPost.setHeader("Content-type", "application/json");
        return new DefaultHttpClient().execute(httpPost);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

Se puede hacer algo similar usando Jackson en lugar de Gson. También recomiendo echar un vistazo a Retrofit, que oculta gran parte de este código repetitivo para usted. Para los desarrolladores más experimentados, recomiendo probar RxAndroid .

JJD
fuente
mi aplicación está enviando datos a través del método HttpPut. cuando el servidor recibe una solicitud, responde como datos json. No sé cómo obtener datos de json. por favor dime. CODIGO .
kongkea
@kongkea Por favor, eche un vistazo a la biblioteca de GSON . Es capaz de analizar el archivo JSON en objetos Java.
JJD
@JJD Hasta ahora, lo que sugiere es enviar datos al servidor remoto y es una buena explicación, pero quiere saber cómo analizar el objeto JSON usando el protocolo HTTP. ¿Puedes elaborar tu respuesta con análisis JSON también? Será muy útil para todos los nuevos en esto.
AndroidDev
@AndroidDev Abra una nueva pregunta, ya que esta pregunta trata sobre el envío de datos del cliente al servidor. Siéntase libre de dejar un enlace aquí.
JJD
@JJD está llamando al método abstracto execute()y, por supuesto, ha fallado
Konstantin Konopko
33

Recomiendo usar esto HttpURLConnectionen su lugar HttpGet. Como HttpGetya está obsoleto en el nivel 22 de API de Android.

HttpURLConnection httpcon;  
String url = null;
String data = null;
String result = null;
try {
  //Connect
  httpcon = (HttpURLConnection) ((new URL (url).openConnection()));
  httpcon.setDoOutput(true);
  httpcon.setRequestProperty("Content-Type", "application/json");
  httpcon.setRequestProperty("Accept", "application/json");
  httpcon.setRequestMethod("POST");
  httpcon.connect();

  //Write       
  OutputStream os = httpcon.getOutputStream();
  BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
  writer.write(data);
  writer.close();
  os.close();

  //Read        
  BufferedReader br = new BufferedReader(new InputStreamReader(httpcon.getInputStream(),"UTF-8"));

  String line = null; 
  StringBuilder sb = new StringBuilder();         

  while ((line = br.readLine()) != null) {  
    sb.append(line); 
  }         

  br.close();  
  result = sb.toString();

} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} 
Égida
fuente
5

Demasiado código para esta tarea, consulte esta biblioteca https://github.com/kodart/Httpzoid Is usa GSON internamente y proporciona una API que funciona con objetos. Todos los detalles JSON están ocultos.

Http http = HttpFactory.create(context);
http.get("http://example.com/users")
    .handler(new ResponseHandler<User[]>() {
        @Override
        public void success(User[] users, HttpResponse response) {
        }
    }).execute();
Arturo
fuente
gran solución, desafortunadamente este complemento carece de soporte gradle: /
electronix384128
3

Hay un par de formas de establecer una conexión HHTP y obtener datos de un servicio web RESTFULL. El más reciente es GSON. Pero antes de continuar con GSON, debe tener una idea de la forma más tradicional de crear un cliente HTTP y realizar la comunicación de datos con un servidor remoto. He mencionado ambos métodos para enviar solicitudes POST y GET usando HTTPClient.

/**
 * This method is used to process GET requests to the server.
 * 
 * @param url 
 * @return String
 * @throws IOException
 */
public static String connect(String url) throws IOException {

    HttpGet httpget = new HttpGet(url);
    HttpResponse response;
    HttpParams httpParameters = new BasicHttpParams();
    // Set the timeout in milliseconds until a connection is established.
    // The default value is zero, that means the timeout is not used. 
    int timeoutConnection = 60*1000;
    HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
    // Set the default socket timeout (SO_TIMEOUT) 
    // in milliseconds which is the timeout for waiting for data.
    int timeoutSocket = 60*1000;

    HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
    HttpClient httpclient = new DefaultHttpClient(httpParameters);
    try {

        response = httpclient.execute(httpget);

        HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream instream = entity.getContent();
            result = convertStreamToString(instream);
            //instream.close();
        }
    } 
    catch (ClientProtocolException e) {
        Utilities.showDLog("connect","ClientProtocolException:-"+e);
    } catch (IOException e) {
        Utilities.showDLog("connect","IOException:-"+e); 
    }
    return result;
}


 /**
 * This method is used to send POST requests to the server.
 * 
 * @param URL
 * @param paramenter
 * @return result of server response
 */
static public String postHTPPRequest(String URL, String paramenter) {       

    HttpParams httpParameters = new BasicHttpParams();
    // Set the timeout in milliseconds until a connection is established.
    // The default value is zero, that means the timeout is not used. 
    int timeoutConnection = 60*1000;
    HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
    // Set the default socket timeout (SO_TIMEOUT) 
    // in milliseconds which is the timeout for waiting for data.
    int timeoutSocket = 60*1000;

    HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
    HttpClient httpclient = new DefaultHttpClient(httpParameters);
    HttpPost httppost = new HttpPost(URL);
    httppost.setHeader("Content-Type", "application/json");
    try {
        if (paramenter != null) {
            StringEntity tmp = null;
            tmp = new StringEntity(paramenter, "UTF-8");
            httppost.setEntity(tmp);
        }
        HttpResponse httpResponse = null;
        httpResponse = httpclient.execute(httppost);
        HttpEntity entity = httpResponse.getEntity();
        if (entity != null) {
            InputStream input = null;
            input = entity.getContent();
            String res = convertStreamToString(input);
            return res;
        }
    } 
     catch (Exception e) {
        System.out.print(e.toString());
    }
    return null;
}
Mike Clark
fuente