¿Cómo hago una solicitud http usando cookies en Android?

121

Me gustaría hacer una solicitud http a un servidor remoto mientras manejo correctamente las cookies (por ejemplo, almacenar cookies enviadas por el servidor y enviarlas cuando realizo solicitudes posteriores). Sería bueno conservar todas y cada una de las cookies, pero en realidad la única que me importa es la cookie de sesión.

Con java.net, parece que la forma preferida de hacer esto es usar java.net.CookieHandler (clase base abstracta) y java.net.CookieManager (implementación concreta). Android tiene java.net.CookieHandler, pero no parece tener java.net.CookieManager.

Podría codificarlo todo a mano inspeccionando los encabezados http, pero parece que debe haber una manera más fácil.

¿Cuál es la forma correcta de hacer solicitudes http en Android mientras se conservan las cookies?

emmby
fuente
¿Has probado org.apache.http.cookie ?
Jack L.
3
Solo como una nota más de dos años después: java.net.CookieManagerahora es compatible con Android desde la versión 2.3 (API nivel 9): developer.android.com/reference/java/net/CookieManager.html
Slauma

Respuestas:

92

Resulta que Google Android viene con Apache HttpClient 4.0, y pude descubrir cómo hacerlo usando el ejemplo de "Inicio de sesión basado en formularios" en los documentos de 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
fuente
11
¿Puedo saber cómo configurar las cookies en la URL de solicitud para verificar si la sesión es válida o no?
Praveen
GRACIAS por presentarme a BasicNameValuePairs. Ellos me ayudaron.
bhekman
3
Entiendo The method getCookieStore() is undefined for the type HttpClient, ¿tengo que cambiarme List<Cookie> cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();? Porque si lo hago, funciona.
Francisco Corrales Morales
@Praveen Eche un vistazo aquí para guardar Cookies: stackoverflow.com/a/5989115/2615737
Francisco Corrales Morales
@emmby: desafortunado módulo de apache Android desaprobado. Así que ahora su respuesta no es útil. ¿Hay otra forma de hacer esto con HttpURLConnection?
Milad Faridnia
9

Una cookie es solo otro encabezado HTTP. Siempre puede configurarlo mientras realiza una llamada HTTP con la biblioteca apache o con HTTPUrlConnection. De cualquier manera, debería poder leer y configurar cookies HTTP de esta manera.

Puedes leer este artículo para más información.

Puedo compartir mi paz de código para demostrar lo fácil que puede hacerlo.

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
fuente
Esto me ayudó mucho, +1 get.setHeader ("Cookie", "PHPSESSID =" + token + ";"); hacer el trabajo
Oussaki
@Hesam: desafortunatley Android módulo de apache en desuso. Así que ahora su respuesta no es útil. ¿Hay otra forma de hacer esto con HttpURLConnection?
Milad Faridnia
7

Dado que la biblioteca Apache está en desuso , para aquellos que quieran usar HttpURLConncetion, escribí esta clase para enviar Obtener y Publicar Solicitud con la ayuda de esta respuesta :

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
fuente
2
Buena clase Milad! Me ayudó mucho ! Ahora, me preguntaba si quería guardar la cookie para que estuviera disponible si el usuario mataba la aplicación y la lanzaba de nuevo, qué exactamente debería almacenar y dónde (cómo)
Ki Jéy
1

No trabajo con Google Android, pero creo que encontrarás que no es tan difícil hacer que esto funcione. Si lees la parte relevante del tutorial de Java , verás que un manejador de cookies registrado recibe devoluciones de llamada del código HTTP.

Entonces, si no hay un valor predeterminado (¿ha verificado si CookieHandler.getDefault()realmente es nulo?), Simplemente puede extender CookieHandler, implementar put / get y hacer que funcione de manera bastante automática. Asegúrese de considerar el acceso concurrente y cosas similares si va por esa ruta.

editar: Obviamente, tendría que establecer una instancia de su implementación personalizada como el controlador predeterminado CookieHandler.setDefault()para recibir las devoluciones de llamada. Olvidé mencionar eso.

wds
fuente