Jak wysłać żądanie POST w JSON za pomocą HTTPClient w systemie Android?

111

Próbuję dowiedzieć się, jak POST JSON z Androida przy użyciu HTTPClient. Od jakiegoś czasu próbuję to rozgryźć, znalazłem wiele przykładów w Internecie, ale nie mogę zmusić żadnego z nich do działania. Uważam, że dzieje się tak z powodu mojego ogólnego braku wiedzy na temat JSON / sieci. Wiem, że istnieje wiele przykładów, ale czy ktoś mógłby wskazać mi rzeczywisty samouczek? Szukam procesu krok po kroku z kodem i wyjaśnieniem, dlaczego wykonujesz każdy krok lub co robi ten krok. Nie musi to być skomplikowana, prosta próba.

Ponownie, wiem, że jest mnóstwo przykładów, naprawdę szukam przykładu z wyjaśnieniem, co dokładnie się dzieje i dlaczego tak się dzieje.

Jeśli ktoś wie o dobrej książce o Androidzie na ten temat, daj mi znać.

Jeszcze raz dziękuję za pomoc @terrance, oto kod, który opisałem poniżej

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
źródło
Może możesz zamieścić jeden z przykładów, których nie możesz uruchomić? Gdy coś zadziała, dowiesz się, jak poszczególne elementy pasują do siebie.
fredw

Odpowiedzi:

157

W tej odpowiedzi korzystam z przykładu opublikowanego przez Justina Grammensa .

O JSON

JSON to skrót od JavaScript Object Notation. We właściwościach JavaScript można odwoływać się zarówno w ten sposób, object1.namejak i w ten sposób object['name'];. Przykład z artykułu wykorzystuje ten bit JSON.

Obiekt
wentylatora Parts A z adresem e-mail jako kluczem i wartością [email protected]

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

Zatem odpowiednikiem obiektu byłoby fan.email;or fan['email'];. Obie miałyby tę samą wartość '[email protected]'.

O żądaniu HttpClient

Poniżej opisano, czego nasz autor użył do wykonania żądania HttpClient . W ogóle nie twierdzę, że jestem ekspertem w tej dziedzinie, więc jeśli ktoś ma lepszy sposób na sformułowanie części terminologii, nie krępuj się.

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

Jeśli nie znasz Mapstruktury danych, zapoznaj się z dokumentacją Java Map . Krótko mówiąc, mapa jest podobna do słownika lub skrótu.

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;
}

Nie krępuj się komentować wszelkich pytań, które pojawiają się w związku z tym postem lub jeśli nie powiedziałem czegoś jasnego, lub jeśli nie poruszyłem czegoś, co nadal jest dla Ciebie zdezorientowane ... itd., Co naprawdę pojawia się w twojej głowie.

(Zrezygnuję, jeśli Justin Grammens się nie zgodzi. Ale jeśli nie, to dziękuję Justinowi za to, że był cool.)

Aktualizacja

Po prostu przypadkiem otrzymałem komentarz o tym, jak używać kodu i zdałem sobie sprawę, że wystąpił błąd w typie zwrotu. Podpis metody został ustawiony tak, aby zwracał ciąg, ale w tym przypadku nic nie zwracał. Zmieniłem sygnaturę na HttpResponse i skieruję Cię do tego linku na stronie Uzyskiwanie odpowiedzi Body of HttpResponse . Zmienna ścieżki to adres URL i zaktualizowałem, aby naprawić błąd w kodzie.

Terrance
źródło
Dzięki @Terrance. Więc w innej klasie tworzy mapę, która ma różne klucze i wartości, które później zostaną zamienione na JSONObjects. Próbowałem zaimplementować coś podobnego, ale nie mam też doświadczenia z mapami, dodam kod tego, co próbowałem zaimplementować do mojego oryginalnego postu. Twoje wyjaśnienie tego, co się działo od tamtej pory, udało mi się uruchomić, tworząc obiekty JSONObject z zakodowanymi na stałe nazwami i wartościami. Dzięki!
Woot, cieszę się, że mogłem pomóc.
Terrance,
Justin mówi, że to akceptuje. Powinien już mieć wystarczająco dużo reputacji, aby przyjść i zostawić komentarz.
Abizern
Chcę użyć tego kodu. Jak mam się do tego zabrać? Proszę określić, jaka jest zmienna ścieżki i co ma zostać zwrócone, abym po stronie java mógł pobrać dane.
Prateek,
3
Nie ma powodu dla getJsonObjectFromMap(): JSONObject ma konstruktora, który przyjmuje Map: developer.android.com/reference/org/json/…
pr1001
41

Oto alternatywne rozwiązanie dla odpowiedzi @ Terrance. Możesz łatwo zlecić konwersję. Biblioteka Gson robi wspaniałą pracę konwersji różnych struktur danych język JSON i na odwrót.

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;
}

Podobnie można zrobić, używając Jackson zamiast Gson. Polecam również przyjrzeć się Retrofit, który ukrywa dla ciebie wiele tego standardowego kodu. Bardziej doświadczonym programistom polecam wypróbowanie RxAndroid .

JJD
źródło
moja aplikacja wysyła dane za pomocą metody HttpPut. gdy serwer otrzyma żądanie, odpowiada jako dane json. Nie wiem, jak uzyskać dane z json. Powiedz mi, Proszę. KOD .
kongkea
@kongkea Zajrzyj do biblioteki GSON . Jest w stanie przeanalizować plik JSON na obiekty Java.
JJD
@JJD Jak dotąd sugerujesz wysyłanie danych do zdalnego serwera i jest to miłe wyjaśnienie, ale chcesz wiedzieć, jak przeanalizować obiekt JSON za pomocą protokołu HTTP. Czy możesz rozwinąć swoją odpowiedź również za pomocą analizy JSON. Będzie to bardzo pomocne dla każdego, kto jest w tym nowy.
AndroidDev
@AndroidDev Proszę otworzyć nowe pytanie, ponieważ dotyczy ono wysyłania danych z klienta na serwer. Zapraszam do umieszczenia linku tutaj.
JJD,
@JJD wywołujesz metodę abstrakcyjną execute()i oczywiście się nie udało
Konstantin Konopko
33

Zalecam używanie tego HttpURLConnectionzamiast tego HttpGet. Jak HttpGetjuż jest przestarzałe na poziomie 22 interfejsu API systemu 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();
} 
Egida
źródło
5

Za dużo kodu do tego zadania, pobierz tę bibliotekę https://github.com/kodart/Httpzoid Wykorzystuje wewnętrznie GSON i zapewnia API, które działa z obiektami. Wszystkie szczegóły JSON są ukryte.

Http http = HttpFactory.create(context);
http.get("http://example.com/users")
    .handler(new ResponseHandler<User[]>() {
        @Override
        public void success(User[] users, HttpResponse response) {
        }
    }).execute();
Arthur
źródło
świetne rozwiązanie, niestety ta wtyczka nie obsługuje gradle: /
electronix384128
3

Istnieje kilka sposobów nawiązania połączenia HHTP i pobrania danych z usługi sieciowej RESTFULL. Najnowszy to GSON. Ale zanim przejdziesz do GSON, musisz mieć pojęcie o najbardziej tradycyjnym sposobie tworzenia klienta HTTP i komunikacji danych ze zdalnym serwerem. Wspomniałem o obu metodach wysyłania żądań POST i GET przy użyciu 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
źródło