Comment faire une requête http en utilisant des cookies sur Android?

121

Je souhaite faire une requête http à un serveur distant tout en gérant correctement les cookies (par exemple, en stockant les cookies envoyés par le serveur et en envoyant ces cookies lorsque je fais des demandes ultérieures). Ce serait bien de conserver tous les cookies, mais le seul qui me tient à cœur est le cookie de session.

Avec java.net, il semble que la meilleure façon de procéder consiste à utiliser java.net.CookieHandler (classe de base abstraite) et java.net.CookieManager (implémentation concrète). Android a java.net.CookieHandler, mais il ne semble pas avoir java.net.CookieManager.

Je pourrais tout coder à la main en inspectant les en-têtes http, mais il semble qu'il doit y avoir un moyen plus simple.

Quelle est la bonne façon de faire des requêtes http sur Android tout en préservant les cookies?

emmby
la source
Avez-vous essayé org.apache.http.cookie ?
Jack L.
3
Juste une note plus de deux ans plus tard: java.net.CookieManagerest maintenant pris en charge dans Android depuis la version 2.3 (API niveau 9): developer.android.com/reference/java/net/CookieManager.html
Slauma

Réponses:

92

Il s'avère que Google Android est livré avec Apache HttpClient 4.0, et j'ai pu comprendre comment le faire en utilisant l'exemple de «connexion basée sur un formulaire» dans la documentation HttpClient :

https://github.com/apache/httpcomponents-client/blob/master/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientFormLogin.java


import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

/**
 * A example that demonstrates how HttpClient APIs can be used to perform
 * form-based logon.
 */
public class ClientFormLogin {

    public static void main(String[] args) throws Exception {

        DefaultHttpClient httpclient = new DefaultHttpClient();

        HttpGet httpget = new HttpGet("https://portal.sun.com/portal/dt");

        HttpResponse response = httpclient.execute(httpget);
        HttpEntity entity = response.getEntity();

        System.out.println("Login form get: " + response.getStatusLine());
        if (entity != null) {
            entity.consumeContent();
        }
        System.out.println("Initial set of cookies:");
        List<Cookie> cookies = httpclient.getCookieStore().getCookies();
        if (cookies.isEmpty()) {
            System.out.println("None");
        } else {
            for (int i = 0; i < cookies.size(); i++) {
                System.out.println("- " + cookies.get(i).toString());
            }
        }

        HttpPost httpost = new HttpPost("https://portal.sun.com/amserver/UI/Login?" +
                "org=self_registered_users&" +
                "goto=/portal/dt&" +
                "gotoOnFail=/portal/dt?error=true");

        List <NameValuePair> nvps = new ArrayList <NameValuePair>();
        nvps.add(new BasicNameValuePair("IDToken1", "username"));
        nvps.add(new BasicNameValuePair("IDToken2", "password"));

        httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));

        response = httpclient.execute(httpost);
        entity = response.getEntity();

        System.out.println("Login form get: " + response.getStatusLine());
        if (entity != null) {
            entity.consumeContent();
        }

        System.out.println("Post logon cookies:");
        cookies = httpclient.getCookieStore().getCookies();
        if (cookies.isEmpty()) {
            System.out.println("None");
        } else {
            for (int i = 0; i < cookies.size(); i++) {
                System.out.println("- " + cookies.get(i).toString());
            }
        }

        // When HttpClient instance is no longer needed, 
        // shut down the connection manager to ensure
        // immediate deallocation of all system resources
        httpclient.getConnectionManager().shutdown();        
    }
}
emmby
la source
11
puis-je savoir comment définir les cookies sur l'URL de demande pour vérifier si la session est valide ou non?
Praveen
MERCI de m'avoir présenté BasicNameValuePairs. Ils m'ont aidé.
bhekman
3
Je reçois The method getCookieStore() is undefined for the type HttpClient, dois-je changer pour List<Cookie> cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();? Parce que si je le fais, ça marche.
Francisco Corrales Morales
@Praveen Jetez un œil ici pour enregistrer les cookies: stackoverflow.com/a/5989115/2615737
Francisco Corrales Morales
@emmby: module Apache obsolète Android unfortunateley. Donc, pour le moment, sa réponse n'est pas utile. Y a-t-il un autre moyen de le faire avec HttpURLConnection?
Milad Faridnia
9

Un cookie n'est qu'un autre en-tête HTTP. Vous pouvez toujours le définir lors d'un appel HTTP avec la bibliothèque apache ou avec HTTPUrlConnection. Dans tous les cas, vous devriez pouvoir lire et définir les cookies HTTP de cette manière.

Vous pouvez lire cet article pour plus d'informations.

Je peux partager ma paix de code pour démontrer à quel point vous pouvez le faire facilement.

public static String getServerResponseByHttpGet(String url, String token) {

        try {
            HttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(url);
            get.setHeader("Cookie", "PHPSESSID=" + token + ";");
            Log.d(TAG, "Try to open => " + url);

            HttpResponse httpResponse = client.execute(get);
            int connectionStatusCode = httpResponse.getStatusLine().getStatusCode();
            Log.d(TAG, "Connection code: " + connectionStatusCode + " for request: " + url);

            HttpEntity entity = httpResponse.getEntity();
            String serverResponse = EntityUtils.toString(entity);
            Log.d(TAG, "Server response for request " + url + " => " + serverResponse);

            if(!isStatusOk(connectionStatusCode))
                return null;

            return serverResponse;

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
Hesam
la source
Cela m'aide beaucoup, +1 get.setHeader ("Cookie", "PHPSESSID =" + token + ";"); faire le travail
Oussaki
@Hesam: module apache déprécié Android unfortunatley. Donc, pour le moment, sa réponse n'est pas utile. Y a-t-il un autre moyen de le faire avec HttpURLConnection?
Milad Faridnia
7

Étant donné que la bibliothèque Apache est obsolète , pour ceux qui souhaitent l'utiliser HttpURLConncetion, j'ai écrit cette classe pour envoyer Get and Post Request à l'aide de cette réponse :

public class WebService {

static final String COOKIES_HEADER = "Set-Cookie";
static final String COOKIE = "Cookie";

static CookieManager msCookieManager = new CookieManager();

private static int responseCode;

public static String sendPost(String requestURL, String urlParameters) {

    URL url;
    String response = "";
    try {
        url = new URL(requestURL);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(15000);
        conn.setConnectTimeout(15000);
        conn.setRequestMethod("POST");

        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");

        if (msCookieManager.getCookieStore().getCookies().size() > 0) {
            //While joining the Cookies, use ',' or ';' as needed. Most of the server are using ';'
            conn.setRequestProperty(COOKIE ,
                    TextUtils.join(";", msCookieManager.getCookieStore().getCookies()));
        }

        conn.setDoInput(true);
        conn.setDoOutput(true);

        OutputStream os = conn.getOutputStream();
        BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(os, "UTF-8"));

        if (urlParameters != null) {
            writer.write(urlParameters);
        }
        writer.flush();
        writer.close();
        os.close();

        Map<String, List<String>> headerFields = conn.getHeaderFields();
        List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);

        if (cookiesHeader != null) {
            for (String cookie : cookiesHeader) {
                msCookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
            }
        }

        setResponseCode(conn.getResponseCode());

        if (getResponseCode() == HttpsURLConnection.HTTP_OK) {

            String line;
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            while ((line = br.readLine()) != null) {
                response += line;
            }
        } else {
            response = "";
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return response;
}


// HTTP GET request
public static String sendGet(String url) throws Exception {

    URL obj = new URL(url);
    HttpURLConnection con = (HttpURLConnection) obj.openConnection();

    // optional default is GET
    con.setRequestMethod("GET");

    //add request header 
    con.setRequestProperty("User-Agent", "Mozilla");
    /*
    * /programming/16150089/how-to-handle-cookies-in-httpurlconnection-using-cookiemanager
    * Get Cookies form cookieManager and load them to connection:
     */
    if (msCookieManager.getCookieStore().getCookies().size() > 0) {
        //While joining the Cookies, use ',' or ';' as needed. Most of the server are using ';'
        con.setRequestProperty(COOKIE ,
                TextUtils.join(";", msCookieManager.getCookieStore().getCookies()));
    }

    /*
    * /programming/16150089/how-to-handle-cookies-in-httpurlconnection-using-cookiemanager
    * Get Cookies form response header and load them to cookieManager:
     */
    Map<String, List<String>> headerFields = con.getHeaderFields();
    List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);
    if (cookiesHeader != null) {
        for (String cookie : cookiesHeader) {
            msCookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
        }
    }


    int responseCode = con.getResponseCode();

    BufferedReader in = new BufferedReader(
            new InputStreamReader(con.getInputStream()));
    String inputLine;
    StringBuffer response = new StringBuffer();

    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);
    }
    in.close();

    return response.toString();
}

public static void setResponseCode(int responseCode) {
    WebService.responseCode = responseCode;
    Log.i("Milad", "responseCode" + responseCode);
}


public static int getResponseCode() {
    return responseCode;
}
}
Milad Faridnia
la source
2
Belle classe Milad! Cela m'a beaucoup aidé ! Maintenant, je me demandais si je voulais enregistrer le cookie pour qu'il soit disponible si l'utilisateur a tué l'application et l'a
relancée
1

Je ne travaille pas avec Google Android mais je pense que vous constaterez que ce n'est pas si difficile de faire fonctionner cela. Si vous lisez le bit correspondant du didacticiel java, vous verrez qu'un gestionnaire de cookies enregistré reçoit des rappels du code HTTP.

Donc, s'il n'y a pas de valeur par défaut (avez-vous vérifié si la valeur CookieHandler.getDefault()est vraiment nulle?), Vous pouvez simplement étendre CookieHandler, implémenter put / get et le faire fonctionner à peu près automatiquement. Assurez-vous de considérer l'accès simultané et autres si vous suivez cette voie.

edit: De toute évidence, vous devrez définir une instance de votre implémentation personnalisée comme gestionnaire par défaut CookieHandler.setDefault()pour recevoir les rappels. J'ai oublié de le mentionner.

wds
la source