Как сделать http-запрос с помощью файлов cookie на Android?

121

Я хотел бы сделать http-запрос к удаленному серверу, правильно обрабатывая файлы cookie (например, сохраняя файлы cookie, отправленные сервером, и отправляя эти файлы cookie, когда я делаю последующие запросы). Было бы неплохо сохранить все файлы cookie, но на самом деле меня волнует только файл cookie сеанса.

С java.net кажется, что предпочтительный способ сделать это - использовать java.net.CookieHandler (абстрактный базовый класс) и java.net.CookieManager (конкретная реализация). В Android есть java.net.CookieHandler, но, похоже, нет java.net.CookieManager.

Я мог бы все это закодировать вручную, просмотрев заголовки http, но похоже, что должен быть более простой способ.

Как правильно выполнять HTTP-запросы на Android при сохранении файлов cookie?

emmby
источник
Вы пробовали org.apache.http.cookie ?
Джек Л.
3
В качестве примечания более чем через два года: java.net.CookieManagerтеперь поддерживается в Android, начиная с версии 2.3 (уровень API 9): developer.android.com/reference/java/net/CookieManager.html
Slauma

Ответы:

92

Оказывается, Google Android поставляется с Apache HttpClient 4.0, и я смог выяснить, как это сделать, используя пример «Вход на основе формы» в документации 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
источник
11
Могу ли я узнать, как установить файлы cookie на URL-адрес запроса, чтобы проверить, действителен ли сеанс?
Praveen
СПАСИБО за то, что познакомили меня с BasicNameValuePairs. Они мне помогли.
bhekman
3
Я понимаю The method getCookieStore() is undefined for the type HttpClient, мне нужно перейти на List<Cookie> cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();? Потому что если я это сделаю, это сработает.
Франсиско Корралес Моралес
@Praveen Взгляните сюда, чтобы сохранить файлы cookie: stackoverflow.com/a/5989115/2615737
Франсиско Корралес Моралес,
@emmby: к сожалению, Android устарел модуль apache. Так что сейчас его ответ бесполезен. Есть ли другой способ сделать это с помощью HttpURLConnection?
Милад Фаридния
9

Файл cookie - это просто еще один заголовок HTTP. Вы всегда можете установить его при выполнении HTTP-вызова с библиотекой apache или с HTTPUrlConnection. В любом случае вы сможете читать и устанавливать файлы cookie HTTP таким образом.

Вы можете прочитать эту статью для получения дополнительной информации.

Я могу поделиться своим кодом, чтобы продемонстрировать, насколько легко вы можете это сделать.

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
источник
Это мне очень помогло, +1 get.setHeader ("Cookie", "PHPSESSID =" + token + ";"); делать работу
Oussaki
@Hesam: к сожалению, Android устарел модуль apache. Так что сейчас его ответ бесполезен. Есть ли другой способ сделать это с помощью HttpURLConnection?
Милад Фаридния
7

Поскольку библиотека Apache устарела , для тех, кто хочет ее использовать HttpURLConncetion, я написал этот класс для отправки запросов Get и Post с помощью этого ответа :

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;
}
}
Милад Фаридния
источник
2
Хороший класс, Милад! Это мне очень помогло ! Теперь мне было интересно, хочу ли я сохранить файл cookie, чтобы он был доступен, если пользователь убил приложение и запустил его снова, что именно я должен хранить и где (как)
Ki Jéy
1

Я не работаю с google android, но думаю, вы обнаружите, что заставить это работать не так уж и сложно. Если вы прочтете соответствующий фрагмент руководства по java, вы увидите, что зарегистрированный обработчик файлов cookie получает обратные вызовы из кода HTTP.

Итак, если нет значения по умолчанию (вы проверили, CookieHandler.getDefault()действительно ли оно равно нулю?), Вы можете просто расширить CookieHandler, реализовать put / get и заставить его работать в значительной степени автоматически. Не забудьте рассмотреть возможность одновременного доступа и т.п., если вы идете по этому пути.

edit: Очевидно, вам придется установить экземпляр своей пользовательской реализации в качестве обработчика по умолчанию CookieHandler.setDefault()для получения обратных вызовов. Забыл об этом упомянуть.

WDS
источник