Jak wysłać żądanie http przy użyciu plików cookie w systemie Android?

121

Chciałbym wysłać zapytanie http do zdalnego serwera przy prawidłowej obsłudze ciasteczek (np. Przechowywanie ciasteczek wysyłanych przez serwer i wysyłanie tych ciasteczek przy kolejnych zapytaniach). Byłoby miło zachować wszystkie pliki cookie, ale tak naprawdę jedyne, na czym mi zależy, to sesyjne.

Wydaje się, że w przypadku java.net preferowanym sposobem jest użycie java.net.CookieHandler (abstrakcyjna klasa bazowa) i java.net.CookieManager (konkretna implementacja). Android ma java.net.CookieHandler, ale wygląda na to, że nie ma java.net.CookieManager.

Mógłbym to wszystko zakodować ręcznie, sprawdzając nagłówki http, ale wydaje się, że musi być prostszy sposób.

Jaki jest właściwy sposób wysyłania żądań http w systemie Android przy zachowaniu plików cookie?

emmby
źródło
Czy próbowałeś już org.apache.http.cookie ?
Jack L.,
3
Uwaga, ponad dwa lata później: java.net.CookieManagerjest teraz obsługiwany w Androidzie od wersji 2.3 (poziom API 9): developer.android.com/reference/java/net/CookieManager.html
Slauma

Odpowiedzi:

92

Okazuje się, że Google Android jest dostarczany z Apache HttpClient 4.0 i udało mi się dowiedzieć, jak to zrobić, korzystając z przykładu „Logowanie na podstawie formularza” w dokumentacji 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
źródło
11
czy mogę wiedzieć, jak ustawić pliki cookie na adres URL żądania, aby sprawdzić, czy sesja jest ważna, czy nie?
Praveen,
DZIĘKUJĘ za wprowadzenie mnie do BasicNameValuePairs. Pomogli mi.
bhekman
3
Dostaję The method getCookieStore() is undefined for the type HttpClient, czy muszę się zmienić List<Cookie> cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();? Bo jeśli tak, to działa.
Francisco Corrales Morales
@Praveen Spójrz tutaj, aby zapisać pliki cookie: stackoverflow.com/a/5989115/2615737
Francisco Corrales Morales
@emmby: unfortunateley android przestarzały moduł apache. Więc teraz jego odpowiedź nie jest pomocna. Czy jest inny sposób na zrobienie tego z HttpURLConnection?
Milad Faridnia
9

Plik cookie to po prostu kolejny nagłówek HTTP. Zawsze możesz to ustawić podczas wykonywania wywołania HTTP z biblioteką Apache lub HTTPUrlConnection. Tak czy inaczej, powinieneś być w stanie odczytywać i ustawiać pliki cookie HTTP w ten sposób.

Możesz przeczytać ten artykuł, aby uzyskać więcej informacji.

Mogę podzielić się swoim kodem, aby pokazać, jak łatwo możesz to zrobić.

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
źródło
To mi bardzo pomogło, +1 get.setHeader ("Cookie", "PHPSESSID =" + token + ";"); wykonaj pracę
Oussaki
@Hesam: unfortunatley Android przestarzały moduł Apache. Więc teraz jego odpowiedź nie jest pomocna. Czy jest inny sposób na zrobienie tego z HttpURLConnection?
Milad Faridnia
7

Ponieważ biblioteka Apache jest przestarzała , dla tych, którzy chcą z niej korzystać HttpURLConncetion, napisałem tę klasę, aby wysyłać żądanie pobierania i wysyłania za pomocą tej odpowiedzi :

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
źródło
2
Nice Class Milad! Bardzo mi to pomogło! Teraz zastanawiałem się, czy chciałbym zapisać plik cookie, aby był dostępny, jeśli użytkownik zabił aplikację i uruchomił ją ponownie, co dokładnie powinienem przechowywać i gdzie (jak)
Ki Jéy
1

Nie pracuję z Google Android, ale myślę, że nie jest to takie trudne. Jeśli przeczytasz odpowiedni fragment samouczka Java , zobaczysz, że zarejestrowany program obsługi plików cookie otrzymuje wywołania zwrotne z kodu HTTP.

Więc jeśli nie ma wartości domyślnej (czy sprawdziłeś, czy CookieHandler.getDefault()naprawdę jest null?), Możesz po prostu rozszerzyć CookieHandler, zaimplementować metodę put / get i sprawić, by działała prawie automatycznie. Pamiętaj, aby rozważyć jednoczesny dostęp i tym podobne, jeśli wybierzesz tę trasę.

edycja: Oczywiście musiałbyś ustawić wystąpienie swojej niestandardowej implementacji jako domyślną procedurę obsługi, CookieHandler.setDefault()aby otrzymywać wywołania zwrotne. Zapomniałem o tym wspomnieć.

wds
źródło