Wie mache ich eine http-Anfrage mit Cookies auf Android?

121

Ich möchte eine http-Anfrage an einen Remote-Server senden, während Cookies ordnungsgemäß verarbeitet werden (z. B. Speichern von vom Server gesendeten Cookies und Senden dieser Cookies, wenn ich nachfolgende Anfragen stelle). Es wäre schön, alle Cookies aufzubewahren, aber das einzige, was mich interessiert, ist das Sitzungscookie.

Bei java.net scheint die bevorzugte Methode die Verwendung von java.net.CookieHandler (abstrakte Basisklasse) und java.net.CookieManager (konkrete Implementierung) zu sein. Android hat java.net.CookieHandler, aber es scheint nicht java.net.CookieManager zu haben.

Ich könnte alles von Hand codieren, indem ich http-Header inspiziere, aber es scheint, dass es einen einfacheren Weg geben muss.

Was ist der richtige Weg, um http-Anfragen unter Android zu stellen und gleichzeitig Cookies zu erhalten?

emmby
quelle
3
Nur als Hinweis mehr als zwei Jahre später: java.net.CookieManager
Wird

Antworten:

92

Es stellt sich heraus, dass Google Android mit Apache HttpClient 4.0 ausgeliefert wird, und ich konnte anhand des Beispiels "Formularbasierte Anmeldung" in den HttpClient-Dokumenten herausfinden, wie dies funktioniert :

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
quelle
11
Kann ich wissen, wie die Cookies auf die Anforderungs-URL gesetzt werden, um zu überprüfen, ob die Sitzung gültig ist oder nicht?
Praveen
DANKE, dass Sie mich mit BasicNameValuePairs bekannt gemacht haben. Sie haben mir geholfen.
Bhekman
3
Ich bekomme The method getCookieStore() is undefined for the type HttpClient, muss ich wechseln zu List<Cookie> cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();? Denn wenn ich es tue, funktioniert es.
Francisco Corrales Morales
@Praveen Schauen Sie hier, um Cookies zu speichern: stackoverflow.com/a/5989115/2615737
Francisco Corrales Morales
@emmby: unglücklicherweise Android veraltetes Apache-Modul. Im Moment ist seine Antwort also nicht hilfreich. Gibt es eine andere Möglichkeit, dies mit HttpURLConnection zu tun?
Milad Faridnia
9

Ein Cookie ist nur ein weiterer HTTP-Header. Sie können es jederzeit festlegen, während Sie einen HTTP-Aufruf mit der Apache-Bibliothek oder mit HTTPUrlConnection tätigen. In beiden Fällen sollten Sie in der Lage sein, HTTP-Cookies auf diese Weise zu lesen und zu setzen.

Sie können diesen Artikel für weitere Informationen lesen .

Ich kann meinen Code-Frieden teilen, um zu demonstrieren, wie einfach Sie es machen können.

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
quelle
Dies hilft mir sehr, +1 get.setHeader ("Cookie", "PHPSESSID =" + token + ";"); mach die Arbeit
Oussaki
@ Hesam: Unglücklicherweise veraltetes Android-Apache-Modul. Im Moment ist seine Antwort also nicht hilfreich. Gibt es eine andere Möglichkeit, dies mit HttpURLConnection zu tun?
Milad Faridnia
7

Da die Apache-Bibliothek für diejenigen, die sie verwenden möchten, veraltet ist HttpURLConncetion, habe ich diese Klasse geschrieben, um mithilfe dieser Antwort eine Get- und Post-Anfrage zu senden :

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
quelle
2
Schöne Klasse Milad! Es hat mir sehr geholfen! Jetzt habe ich mich gefragt, ob ich das Cookie speichern möchte, damit es verfügbar ist, wenn der Benutzer die App beendet und erneut gestartet hat. Was genau soll ich speichern und wo (wie)
Ki Jéy
1

Ich arbeite nicht mit Google Android, aber ich denke, Sie werden feststellen, dass es nicht so schwer ist, dies zum Laufen zu bringen. Wenn Sie das entsprechende Bit des Java-Tutorials lesen, werden Sie feststellen, dass ein registrierter Cookie-Handler Rückrufe vom HTTP-Code erhält.

Wenn es also keine Standardeinstellung gibt (haben Sie überprüft, ob sie CookieHandler.getDefault()wirklich null ist?), Können Sie einfach CookieHandler erweitern, put / get implementieren und es so gut wie automatisch zum Laufen bringen. Berücksichtigen Sie den gleichzeitigen Zugriff und dergleichen, wenn Sie diesen Weg gehen.

Bearbeiten: Natürlich müssten Sie eine Instanz Ihrer benutzerdefinierten Implementierung als Standardhandler festlegen CookieHandler.setDefault(), um die Rückrufe zu erhalten. Ich habe vergessen, das zu erwähnen.

wds
quelle