Bagaimana cara membuat permintaan http menggunakan cookie di Android?

121

Saya ingin membuat permintaan http ke server jarak jauh sambil menangani cookie dengan benar (mis. Menyimpan cookie yang dikirim oleh server, dan mengirim cookie tersebut ketika saya membuat permintaan berikutnya). Akan menyenangkan untuk menyimpan setiap dan semua cookie, tetapi satu-satunya yang saya pedulikan adalah cookie sesi.

Dengan java.net, tampaknya cara yang disukai untuk melakukan ini adalah menggunakan java.net.CookieHandler (kelas dasar abstrak) dan java.net.CookieManager (implementasi konkret). Android memiliki java.net.CookieHandler, tetapi tampaknya tidak memiliki java.net.CookieManager.

Saya bisa mengkodekan semuanya dengan tangan dengan memeriksa header http, tetapi sepertinya pasti ada cara yang lebih mudah.

Apa cara yang tepat untuk membuat permintaan http di Android sambil mempertahankan cookie?

emmby
sumber
Sudahkah Anda mencoba org.apache.http.cookie ?
Jack L.
3
Hanya sebagai catatan lebih dari dua tahun kemudian: java.net.CookieManagersekarang didukung di Android sejak versi 2.3 (API level 9): developer.android.com/reference/java/net/CookieManager.html
Slauma

Jawaban:

92

Ternyata Google Android dikirimkan dengan Apache HttpClient 4.0, dan saya dapat mengetahui cara melakukannya menggunakan contoh "Logon berbasis formulir" di dokumen 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
sumber
11
bolehkah saya tahu cara menyetel cookie ke Url Permintaan untuk memeriksa sesi apakah valid atau tidak?
Praveen
TERIMA KASIH telah memperkenalkan saya pada BasicNameValuePairs. Mereka membantu saya.
bhekman
3
Saya mengerti The method getCookieStore() is undefined for the type HttpClient, Apakah saya harus berganti ke List<Cookie> cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();? Karena jika saya melakukannya, itu berhasil.
Francisco Corrales Morales
@Praveen Lihat di sini untuk menyimpan Cookies: stackoverflow.com/a/5989115/2615737
Francisco Corrales Morales
@emmby: unfortunateley android deprecated apache module. Jadi sekarang jawabannya tidak membantu. Apakah ada cara lain untuk melakukan ini dengan HttpURLConnection?
Milad Faridnia
9

Cookie hanyalah header HTTP lainnya. Anda selalu dapat menyetelnya saat melakukan panggilan HTTP dengan pustaka apache atau dengan HTTPUrlConnection. Apa pun itu, Anda harus dapat membaca dan menyetel cookie HTTP dengan cara ini.

Anda dapat membaca artikel ini untuk informasi lebih lanjut.

Saya dapat membagikan kedamaian kode saya untuk menunjukkan betapa mudahnya Anda membuatnya.

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
sumber
Ini sangat membantu saya, +1 get.setHeader ("Cookie", "PHPSESSID =" + token + ";"); lakukan pekerjaan
Oussaki
@Hesam: unfortunatley android deprecated apache module. Jadi saat ini jawabannya tidak membantu. Apakah ada cara lain untuk melakukan ini dengan HttpURLConnection?
Milad Faridnia
7

Karena pustaka Apache sudah usang , bagi mereka yang ingin menggunakan HttpURLConncetion, saya menulis kelas ini untuk mengirim Dapatkan dan Kirim Permintaan dengan bantuan jawaban ini :

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
sumber
2
Kelas yang bagus Milad! Itu sangat membantu saya! Sekarang, saya bertanya-tanya, apakah saya ingin menyimpan cookie agar tersedia jika pengguna mematikan aplikasi dan meluncurkannya lagi, apa sebenarnya yang harus saya simpan dan di mana (bagaimana)
Ki Jéy
1

Saya tidak bekerja dengan google android tetapi saya pikir Anda akan menemukan tidak terlalu sulit untuk membuatnya bekerja. Jika Anda membaca sedikit yang relevan dari tutorial java Anda akan melihat bahwa cookiehandler terdaftar mendapat panggilan balik dari kode HTTP.

Jadi jika tidak ada default ( CookieHandler.getDefault()sudahkah Anda memeriksa apakah benar-benar null?) Maka Anda cukup memperluas CookieHandler, mengimplementasikan put / get dan membuatnya bekerja secara otomatis. Pastikan untuk mempertimbangkan akses bersamaan dan sejenisnya jika Anda pergi ke rute itu.

edit: Jelas Anda harus menetapkan contoh implementasi kustom Anda sebagai pengendali default melalui CookieHandler.setDefault()untuk menerima callback. Lupa menyebutkan itu.

wds
sumber