Como faço uma solicitação http usando cookies no Android?

121

Eu gostaria de fazer uma solicitação http para um servidor remoto enquanto manipulava adequadamente os cookies (por exemplo, armazenando cookies enviados pelo servidor e enviando esses cookies quando eu fizer solicitações subsequentes). Seria bom preservar todos e quaisquer cookies, mas realmente o único que me interessa é o cookie de sessão.

Com o java.net, parece que a maneira preferida de fazer isso é usar java.net.CookieHandler (classe base abstrata) e java.net.CookieManager (implementação concreta). O Android tem o java.net.CookieHandler, mas parece não ter o java.net.CookieManager.

Eu poderia codificar tudo manualmente inspecionando os cabeçalhos http, mas parece que deve haver uma maneira mais fácil.

Qual é a maneira correta de fazer solicitações de HTTP no Android e preservar os cookies?

empapar
fonte
Você já experimentou org.apache.http.cookie ?
Jack L.
3
Assim como uma nota mais do que dois anos mais tarde: java.net.CookieManageragora é suportado no Android desde (nível API 9) versão 2.3: developer.android.com/reference/java/net/CookieManager.html
Slauma

Respostas:

92

Acontece que o Google Android é fornecido com o Apache HttpClient 4.0, e eu pude descobrir como fazer isso usando o exemplo "Logon baseado em formulário" nos documentos do 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();        
    }
}
empapar
fonte
11
posso saber como definir os cookies no URL de solicitação para verificar se a sessão é válida ou não?
Praveen
OBRIGADO por me apresentar o BasicNameValuePairs. Eles me ajudaram.
bhekman
3
Eu entendo The method getCookieStore() is undefined for the type HttpClient, eu tenho que mudar para List<Cookie> cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();? Porque se eu fizer, funciona.
Francisco Corrales Morales
@Praveen Dê uma olhada aqui para salvar Cookies: stackoverflow.com/a/5989115/2615737 #
Francisco Corrales Morales
@emmby: infeliz módulo android apache obsoleto. Então, agora, a resposta dele não é útil. Existe outra maneira de fazer isso com o HttpURLConnection?
Milad Faridnia
9

Um cookie é apenas outro cabeçalho HTTP. Você sempre pode configurá-lo ao fazer uma chamada HTTP com a biblioteca apache ou com HTTPUrlConnection. De qualquer maneira, você poderá ler e definir cookies HTTP dessa maneira.

Você pode ler este artigo para obter mais informações.

Posso compartilhar minha paz de código para demonstrar como você pode facilitar.

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
fonte
Isso me ajudou muito, +1 get.setHeader ("Cookie", "PHPSESSID =" + token + ";"); fazer o trabalho
Oussaki
@Hesam: infelizmente, o módulo apache do Android está obsoleto. Então, agora, a resposta dele não é útil. Existe outra maneira de fazer isso com o HttpURLConnection?
Milad Faridnia 12/04/2016
7

Como a biblioteca Apache está obsoleta , para aqueles que desejam usar HttpURLConncetion, escrevi esta classe para enviar Solicitações de Recebimento e Postagem com a ajuda desta resposta :

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
fonte
2
Nice Class Milad! Isto me ajudou bastante ! Agora, eu estava pensando, se eu queria salvar o cookie para que ele esteja disponível se o usuário matou o aplicativo e lançou-lo novamente, o que exatamente deve eu armazenar e onde (como)
Ki Jey
1

Eu não trabalho com o google android, mas acho que você descobrirá que não é tão difícil fazer isso funcionar. Se você ler a parte relevante do tutorial sobre Java, verá que um manipulador de cookies registrado recebe retornos de chamada do código HTTP.

Portanto, se não houver um padrão (você verificou se CookieHandler.getDefault()realmente é nulo?), Pode simplesmente estender o CookieHandler, implementar put / get e fazê-lo funcionar praticamente automaticamente. Certifique-se de considerar o acesso simultâneo e similares se você seguir esse caminho.

editar: obviamente, você teria que definir uma instância da sua implementação personalizada como o manipulador padrão CookieHandler.setDefault()para receber os retornos de chamada. Esqueci de mencionar isso.

wds
fonte