Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Uso de cookies con Android volley library

¿Alguien sabe cómo adjuntar una cookie de sesión a la solicitud utilizando la biblioteca com.android.volley? Cuando inicio una sesión en un Web site me da una galleta de la sesión. El navegador enviaría esa cookie de nuevo con cualquier solicitud posterior. Volley no parece hacer eso, al menos no automáticamente.

Gracias.

  • ¿Qué es la consola.log () de java?
  • ¿Por qué AndroidTestCase.getContext (). GetApplicationContext () devuelve null?
  • ¿Por qué la clase singleton sobrevive a la actividad?
  • Cómo mantener la CPU de 'dormir' cuando la pantalla está apagada en Android?
  • Textura transparente en OpenGL ES para Android
  • ¿Falta com.google.android.maps?
  • GridLayout alinear a los niños dentro de la columna
  • No se reciben los caracteres unicode GCM de Android
  • Compresión de textura de Android OpenGL
  • Navegue por el sistema de archivos de Frambuesa Pi desde android vía bluetooth
  • Extraer la guiñada, el tono y el rollo desde una matriz de rotación
  • Programaticamente, descubre cuántos dedos en el dispositivo multitáctil Android soporta
  • 10 Solutions collect form web for “Uso de cookies con Android volley library”

    Volley en realidad no hace solicitudes HTTP por sí mismo, y por lo tanto no gestiona cookies directamente. En su lugar utiliza una instancia de HttpStack para hacer esto. Hay dos implementaciones principales:

    • HurlStack: Utiliza HttpUrlConnection bajo el capó
    • HttpClientStack: utiliza Apache HttpClient bajo el capó

    La gestión de cookies es responsabilidad de los HttpStacks. Y cada uno maneja las galletas diferentemente.

    Si necesita soportar <2.3, entonces debe usar HttpClientStack:

    Configurar una instancia de HttpClient y pasarla a Volley para usarla bajo la campana:

     // If you need to directly manipulate cookies later on, hold onto this client // object as it gives you access to the Cookie Store DefaultHttpClient httpclient = new DefaultHttpClient(); CookieStore cookieStore = new BasicCookieStore(); httpclient.setCookieStore( cookieStore ); HttpStack httpStack = new HttpClientStack( httpclient ); RequestQueue requestQueue = Volley.newRequestQueue( context, httpStack ); 

    La ventaja con esto vs insertar manualmente las cookies en los encabezados es que se obtiene la gestión de cookies real. Las cookies de su tienda responderán correctamente a los controles HTTP que caducan o los actualizan.

    He ido un paso más allá y sub-clasificado BasicCookieStore para que pueda persistir automáticamente mis cookies en el disco.

    ¡SIN EMBARGO! Si no necesita soportar versiones anteriores de Android. Simplemente utilice este método:

     // CookieStore is just an interface, you can implement it and do things like // save the cookies to disk or what ever. CookieStore cookieStore = new MyCookieStore(); CookieManager manager = new CookieManager( cookieStore, CookiePolicy.ACCEPT_ALL ); CookieHandler.setDefault( manager ); // Optionally, you can just use the default CookieManager CookieManager manager = new CookieManager(); CookieHandler.setDefault( manager ); 

    HttpURLConnection consultará el CookieManager de forma implícita. HttpUrlConnection también es más performant y un poco más limpio para implementar y trabajar con IMO.

    Vmirinov tiene razón!

    He aquí cómo resolví el problema:

    Clase de solicitud:

     public class StringRequest extends com.android.volley.toolbox.StringRequest { private final Map<String, String> _params; /** * @param method * @param url * @param params * A {@link HashMap} to post with the request. Null is allowed * and indicates no parameters will be posted along with request. * @param listener * @param errorListener */ public StringRequest(int method, String url, Map<String, String> params, Listener<String> listener, ErrorListener errorListener) { super(method, url, listener, errorListener); _params = params; } @Override protected Map<String, String> getParams() { return _params; } /* (non-Javadoc) * @see com.android.volley.toolbox.StringRequest#parseNetworkResponse(com.android.volley.NetworkResponse) */ @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { // since we don't know which of the two underlying network vehicles // will Volley use, we have to handle and store session cookies manually MyApp.get().checkSessionCookie(response.headers); return super.parseNetworkResponse(response); } /* (non-Javadoc) * @see com.android.volley.Request#getHeaders() */ @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> headers = super.getHeaders(); if (headers == null || headers.equals(Collections.emptyMap())) { headers = new HashMap<String, String>(); } MyApp.get().addSessionCookie(headers); return headers; } } 

    Y MyApp:

     public class MyApp extends Application { private static final String SET_COOKIE_KEY = "Set-Cookie"; private static final String COOKIE_KEY = "Cookie"; private static final String SESSION_COOKIE = "sessionid"; private static MyApp _instance; private RequestQueue _requestQueue; private SharedPreferences _preferences; public static MyApp get() { return _instance; } @Override public void onCreate() { super.onCreate(); _instance = this; _preferences = PreferenceManager.getDefaultSharedPreferences(this); _requestQueue = Volley.newRequestQueue(this); } public RequestQueue getRequestQueue() { return _requestQueue; } /** * Checks the response headers for session cookie and saves it * if it finds it. * @param headers Response Headers. */ public final void checkSessionCookie(Map<String, String> headers) { if (headers.containsKey(SET_COOKIE_KEY) && headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) { String cookie = headers.get(SET_COOKIE_KEY); if (cookie.length() > 0) { String[] splitCookie = cookie.split(";"); String[] splitSessionId = splitCookie[0].split("="); cookie = splitSessionId[1]; Editor prefEditor = _preferences.edit(); prefEditor.putString(SESSION_COOKIE, cookie); prefEditor.commit(); } } } /** * Adds session cookie to headers if exists. * @param headers */ public final void addSessionCookie(Map<String, String> headers) { String sessionId = _preferences.getString(SESSION_COOKIE, ""); if (sessionId.length() > 0) { StringBuilder builder = new StringBuilder(); builder.append(SESSION_COOKIE); builder.append("="); builder.append(sessionId); if (headers.containsKey(COOKIE_KEY)) { builder.append("; "); builder.append(headers.get(COOKIE_KEY)); } headers.put(COOKIE_KEY, builder.toString()); } } } 

    El código de transporte HTTP predeterminado para Volley es HttpUrlConnection . Si estoy leyendo la documentación correctamente, debe optar por el soporte automático de cookie de sesión:

     CookieManager cookieManager = new CookieManager(); CookieHandler.setDefault(cookieManager); 

    ¿ También debería HttpURLConnection con CookieManager manejar automáticamente las cookies de sesión?

    La solución @Rastio no funciona si hay varios encabezados 'Set-Cookie'. Envolví la tienda de cookies predeterminada CookieManager y antes de agregar una cookie lo guardé en SharedPreferences usando Gson para serializar la cookie.

    Este es un ejemplo de la envoltura de la tienda de galletas:

     import android.content.Context; import android.net.Uri; import android.util.Log; import com.google.gson.Gson; import java.net.CookieManager; import java.net.CookieStore; import java.net.HttpCookie; import java.net.URI; import java.util.List; /** * Class that implements CookieStore interface. This class saves to SharedPreferences the session * cookie. * * Created by lukas. */ public class PersistentCookieStore implements CookieStore { private CookieStore mStore; private Context mContext; private Gson mGson; public PersistentCookieStore(Context context) { // prevent context leaking by getting the application context mContext = context.getApplicationContext(); mGson = new Gson(); // get the default in memory store and if there is a cookie stored in shared preferences, // we added it to the cookie store mStore = new CookieManager().getCookieStore(); String jsonSessionCookie = Prefs.getJsonSessionCookie(mContext); if (!jsonSessionCookie.equals(Prefs.DEFAULT_STRING)) { HttpCookie cookie = mGson.fromJson(jsonSessionCookie, HttpCookie.class); mStore.add(URI.create(cookie.getDomain()), cookie); } } @Override public void add(URI uri, HttpCookie cookie) { if (cookie.getName().equals("sessionid")) { // if the cookie that the cookie store attempt to add is a session cookie, // we remove the older cookie and save the new one in shared preferences remove(URI.create(cookie.getDomain()), cookie); Prefs.saveJsonSessionCookie(mContext, mGson.toJson(cookie)); } mStore.add(URI.create(cookie.getDomain()), cookie); } @Override public List<HttpCookie> get(URI uri) { return mStore.get(uri); } @Override public List<HttpCookie> getCookies() { return mStore.getCookies(); } @Override public List<URI> getURIs() { return mStore.getURIs(); } @Override public boolean remove(URI uri, HttpCookie cookie) { return mStore.remove(uri, cookie); } @Override public boolean removeAll() { return mStore.removeAll(); } } 

    A continuación, para utilizar la tienda de galletas acaba de configurar en el CookieManager y eso es todo!

     CookieManager cookieManager = new CookieManager(new PersistentCookieStore(mContext), CookiePolicy.ACCEPT_ORIGINAL_SERVER); CookieHandler.setDefault(cookieManager); 

    Chicos probar esto en el método onCreate de su AppController.java

      CookieHandler.setDefault(new CookieManager()); 

    Espero que ahorre tiempo de los desarrolladores. He perdido cuatro horas en la depuración y la búsqueda de la solución adecuada.

    Conozco el post y un poco viejo, pero hemos pasado por este problema reciente, tenemos que compartir la sesión de un usuario registrado entre servidores, y la solución del lado del servidor comenzó a requerir un valor que se proporcionará por el lado del cliente, a través de la cookie. Una solución que encontramos fue agregar un parámetro a RequestQueue objeto, el fragmento de código en el método getRequestQueue antes de instanciar el RequestQueue encontrado en el enlace de abajo, y resolver el problema, no sé cómo, pero comenzó a funcionar.

    Visita http://woxiangbo.iteye.com/blog/1769122

     public class App extends Application { public static final String TAG = App.class.getSimpleName(); private static App mInstance; public static synchronized App getInstance() { return App.mInstance; } private RequestQueue mRequestQueue; public <T> void addToRequestQueue( final Request<T> req ) { req.setTag( App.TAG ); this.getRequestQueue().add( req ); } public <T> void addToRequestQueue( final Request<T> req, final String tag ) { req.setTag( TextUtils.isEmpty( tag ) ? App.TAG : tag ); this.getRequestQueue().add( req ); } public void cancelPendingRequests( final Object tag ) { if ( this.mRequestQueue != null ) { this.mRequestQueue.cancelAll( tag ); } } public RequestQueue getRequestQueue() { if ( this.mRequestQueue == null ) { DefaultHttpClient mDefaultHttpClient = new DefaultHttpClient(); final ClientConnectionManager mClientConnectionManager = mDefaultHttpClient.getConnectionManager(); final HttpParams mHttpParams = mDefaultHttpClient.getParams(); final ThreadSafeClientConnManager mThreadSafeClientConnManager = new ThreadSafeClientConnManager( mHttpParams, mClientConnectionManager.getSchemeRegistry() ); mDefaultHttpClient = new DefaultHttpClient( mThreadSafeClientConnManager, mHttpParams ); final HttpStack httpStack = new HttpClientStack( mDefaultHttpClient ); this.mRequestQueue = Volley.newRequestQueue( this.getApplicationContext(), httpStack ); } return this.mRequestQueue; } @Override public void onCreate() { super.onCreate(); App.mInstance = this; } } 

    // establecer valor de token

     ObjectRequest.setHeader( "Cookie", "JSESSIONID=" + tokenValueHere ); 

    Utilice este método para utilizar Volley con cookies para:

    1. Utilice sólo código muy bien probado con licencia bajo licencia Apache 2
    2. Haga tantas solicitudes como desee al mismo tiempo
    3. Asegúrese de que las cookies persisten en el dispositivo
    4. No tener que reinventar la rueda

    Mi servidor utiliza cookies para autenticar y, obviamente, quería asegurar que las cookies persisten en el dispositivo. Así que mi solución fue usar PersistentCookieStore y SerializableCookie clases de Asynchronous Http Client para Android .

    En primer lugar, para permitir las solicitudes concurrentes , se necesita un puerto Apache HttpClient v4.3 para Android, uno que viene con el sistema está desactualizado. Más información aquí . Utilizo Gradle, así es como lo importé:

     dependencies { compile group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.3' } 

    Función para obtener RequestQueue (en mi clase que extiende la aplicación):

     private RequestQueue mRequestQueue; private CloseableHttpClient httpClient; 

     public RequestQueue getRequestQueue() { if (mRequestQueue == null) { httpClient = HttpClients.custom() .setConnectionManager(new PoolingHttpClientConnectionManager()) .setDefaultCookieStore(new PersistentCookieStore(getApplicationContext())) .build(); mRequestQueue = Volley.newRequestQueue(getApplicationContext(), new HttpClientStack(httpClient)); } return mRequestQueue; } 

    Esta es la forma en que la cola de una solicitud

     public <T> void addToRequestQueue(Request<T> req, String tag) { req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); getRequestQueue().add(req); } 

    ¡Eso es!

    Si ya ha comenzado a implementar su aplicación utilizando la biblioteca Loopj, notará que no puede usar la nueva instancia HttpClient en Volley.newRequestQUeue () porque obtendrá varios errores al no cerrar su conexión anterior, etc.

    Errores como:

     java.lang.IllegalStateException: No wrapped connection Invalid use of SingleClientConnManager: connection still allocated. 

    Ahora a veces toma tiempo refactorizar todas tus viejas llamadas de API y reescribirlas usando volley, pero puedes usar volley y loopj al mismo tiempo y compartir un cookiestore entre esos dos hasta que escribas todo en volley (usa volley en vez de loopj, it es mucho mejor 🙂 ).

    Así es como puedes compartir HttpClient y CookieStore desde loopj con volley.

     // For example you initialize loopj first private static AsyncHttpClient client = new AsyncHttpClient(); sCookieStore = new PersistentCookieStore(getSomeContextHere()); client.setTimeout(DEFAULT_TIMEOUT); client.setMaxConnections(12); client.setCookieStore(sCookieStore); client.setThreadPool(((ThreadPoolExecutor) Executors.newCachedThreadPool())); public static RequestQueue getRequestQueue(){ if(mRequestQueue == null){ HttpClient httpclient = KkstrRestClient.getClient().getHttpClient(); ((AbstractHttpClient) httpclient).setCookieStore( ApplicationController.getCookieStore() ); HttpStack httpStack = new HttpClientStack(httpclient); mRequestQueue = Volley.newRequestQueue(getContext(), httpStack); } return mRequestQueue; } 

    Esto me sucedió, empezamos a usar loopj. Después de 50 000 líneas de código y el descubrimiento de que loopj no siempre funciona como esperado, decidimos cambiar a Volley.

    La respuesta de @ CommonsWare es la que yo uso. Sin embargo, parece que KitKat está teniendo algunos errores cuando se hace esto (cuando se crea un CookieManager con CookieStore personalizado que necesita si desea Cookies persistentes). Dado el hecho de que, independientemente de la implementación de la CookieStore que se utiliza, Volley lanzaría una NullpointerException , tuve que crear mi propio CookieHandler … usarlo si lo encuentra útil.

     public class MyCookieHandler extends CookieHandler { private static final String VERSION_ZERO_HEADER = "Set-cookie"; private static final String VERSION_ONE_HEADER = "Set-cookie2"; private static final String COOKIE_HEADER = "Cookie"; private static final String COOKIE_FILE = "Cookies"; private Map<String, Map<String, HttpCookie>> urisMap; private Context context; public MyCookieHandler(Context context) { this.context = context; loadCookies(); } @SuppressWarnings("unchecked") private void loadCookies() { File file = context.getFileStreamPath(COOKIE_FILE); if (file.exists()) try { FileInputStream fis = context.openFileInput(COOKIE_FILE); BufferedReader br = new BufferedReader(new InputStreamReader( fis)); String line = br.readLine(); StringBuilder sb = new StringBuilder(); while (line != null) { sb.append(line); line = br.readLine(); } Log.d("MyCookieHandler.loadCookies", sb.toString()); JSONObject jsonuris = new JSONObject(sb.toString()); urisMap = new HashMap<String, Map<String, HttpCookie>>(); Iterator<String> jsonurisiter = jsonuris.keys(); while (jsonurisiter.hasNext()) { String prop = jsonurisiter.next(); HashMap<String, HttpCookie> cookiesMap = new HashMap<String, HttpCookie>(); JSONObject jsoncookies = jsonuris.getJSONObject(prop); Iterator<String> jsoncookiesiter = jsoncookies.keys(); while (jsoncookiesiter.hasNext()) { String pprop = jsoncookiesiter.next(); cookiesMap.put(pprop, jsonToCookie(jsoncookies.getJSONObject(pprop))); } urisMap.put(prop, cookiesMap); } } catch (Exception e) { e.printStackTrace(); } else { urisMap = new HashMap<String, Map<String, HttpCookie>>(); } } @Override public Map<String, List<String>> get(URI arg0, Map<String, List<String>> arg1) throws IOException { Log.d("MyCookieHandler.get", "getting Cookies for domain: " + arg0.getHost()); Map<String, HttpCookie> cookies = urisMap.get(arg0.getHost()); if (cookies != null) for (Entry<String, HttpCookie> cookie : cookies.entrySet()) { if (cookie.getValue().hasExpired()) { cookies.remove(cookie.getKey()); } } if (cookies == null || cookies.isEmpty()) { Log.d("MyCookieHandler.get", "======"); return Collections.emptyMap(); } Log.d("MyCookieHandler.get", "Cookie : " + TextUtils.join("; ", cookies.values())); Log.d("MyCookieHandler.get", "======"); return Collections.singletonMap(COOKIE_HEADER, Collections .singletonList(TextUtils.join("; ", cookies.values()))); } @Override public void put(URI uri, Map<String, List<String>> arg1) throws IOException { Map<String, HttpCookie> cookies = parseCookies(arg1); Log.d("MyCookieHandler.put", "saving Cookies for domain: " + uri.getHost()); addCookies(uri, cookies); Log.d("MyCookieHandler.put", "Cookie : " + TextUtils.join("; ", cookies.values())); Log.d("MyCookieHandler.put", "======"); } private void addCookies(URI uri, Map<String, HttpCookie> cookies) { if (!cookies.isEmpty()) { if (urisMap.get(uri.getHost()) == null) { urisMap.put(uri.getHost(), cookies); } else { urisMap.get(uri.getHost()).putAll(cookies); } saveCookies(); } } private void saveCookies() { try { FileOutputStream fos = context.openFileOutput(COOKIE_FILE, Context.MODE_PRIVATE); JSONObject jsonuris = new JSONObject(); for (Entry<String, Map<String, HttpCookie>> uris : urisMap .entrySet()) { JSONObject jsoncookies = new JSONObject(); for (Entry<String, HttpCookie> savedCookies : uris.getValue() .entrySet()) { jsoncookies.put(savedCookies.getKey(), cookieToJson(savedCookies.getValue())); } jsonuris.put(uris.getKey(), jsoncookies); } fos.write(jsonuris.toString().getBytes()); fos.close(); Log.d("MyCookieHandler.addCookies", jsonuris.toString()); } catch (Exception e) { e.printStackTrace(); } } private static JSONObject cookieToJson(HttpCookie cookie) { JSONObject jsoncookie = new JSONObject(); try { jsoncookie.put("discard", cookie.getDiscard()); jsoncookie.put("maxAge", cookie.getMaxAge()); jsoncookie.put("secure", cookie.getSecure()); jsoncookie.put("version", cookie.getVersion()); jsoncookie.put("comment", cookie.getComment()); jsoncookie.put("commentURL", cookie.getCommentURL()); jsoncookie.put("domain", cookie.getDomain()); jsoncookie.put("name", cookie.getName()); jsoncookie.put("path", cookie.getPath()); jsoncookie.put("portlist", cookie.getPortlist()); jsoncookie.put("value", cookie.getValue()); } catch (JSONException e) { e.printStackTrace(); } return jsoncookie; } private static HttpCookie jsonToCookie(JSONObject jsonObject) { HttpCookie httpCookie; try { httpCookie = new HttpCookie(jsonObject.getString("name"), jsonObject.getString("value")); if (jsonObject.has("comment")) httpCookie.setComment(jsonObject.getString("comment")); if (jsonObject.has("commentURL")) httpCookie.setCommentURL(jsonObject.getString("commentURL")); if (jsonObject.has("discard")) httpCookie.setDiscard(jsonObject.getBoolean("discard")); if (jsonObject.has("domain")) httpCookie.setDomain(jsonObject.getString("domain")); if (jsonObject.has("maxAge")) httpCookie.setMaxAge(jsonObject.getLong("maxAge")); if (jsonObject.has("path")) httpCookie.setPath(jsonObject.getString("path")); if (jsonObject.has("portlist")) httpCookie.setPortlist(jsonObject.getString("portlist")); if (jsonObject.has("secure")) httpCookie.setSecure(jsonObject.getBoolean("secure")); if (jsonObject.has("version")) httpCookie.setVersion(jsonObject.getInt("version")); return httpCookie; } catch (JSONException e) { e.printStackTrace(); } return null; } private Map<String, HttpCookie> parseCookies(Map<String, List<String>> map) { Map<String, HttpCookie> response = new HashMap<String, HttpCookie>(); for (Entry<String, List<String>> e : map.entrySet()) { String key = e.getKey(); if (key != null && (key.equalsIgnoreCase(VERSION_ONE_HEADER) || key .equalsIgnoreCase(VERSION_ZERO_HEADER))) { for (String cookie : e.getValue()) { try { for (HttpCookie htpc : HttpCookie.parse(cookie)) { response.put(htpc.getName(), htpc); } } catch (Exception e1) { Log.e("MyCookieHandler.parseCookies", "Error parsing cookies", e1); } } } } return response; } } 

    Esta respuesta no ha sido probada a fondo. Utilicé JSON para serializar Cookies, porque bien, esa clase no implementa Serializable y es final.

    Aquí está uno de los ejemplos de trabajo más simples. No me gusta RESTO que no es restfull. Pero supongo que todo va como una experiencia de aprendizaje. Lo más importante a notar en el siguiente ejemplo es que curlget.php no tiene session_start. El idioma que usas para escribir esa parte depende de ti. En el ejemplo siguiente podría ser cualquier cosa de java a óxido. También podría localizar en cualquier lugar.

    Login.php

    Código PHP:

     <?php session_start(); //we store any POST/GET request to session $_SESSION['un'] = $_REQUEST['username']; userinfo.php PHP Code: <?php session_start(); echo json_encode($_SESSION['un']); 

    Curlget.php Código PHP:

     <?php $ch = curl_init(); //we do login and get the session_id in from it's responce headers curl_setopt($ch, CURLOPT_URL,"http://localhost/login.php"); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS,"username=test"); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec ($ch); //we get the cookie from response header with the hardest possible way //most platforms have tools for these preg_match_all('/^Set-Cookie:\s*([^\r\n]*)/mi', $result, $ms); $cookies = array(); foreach ($ms[1] as $m) { list($name, $value) = explode('=', $m, 2); $cookies[$name] = $value; } $parts = explode(";",$cookies['PHPSESSID']); //The SessionId finally $SID = $parts[0]; curl_close ($ch); 

    // GET solicitud utilizando el SID de la llamada anterior

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.