wake-up-neo.com

Verwendung von Cookies für verschiedene Aktivitäten bei der Verwendung von HttpClient

Ich versuche, eine einfache App im HTML-Code einer Website zu lesen und diese zu transformieren, um eine leicht lesbare Benutzeroberfläche in Android zu erstellen (Dies ist eine Übung zum Erlernen von Android, nicht um eine brauchbare App zu erstellen). Das Problem, das ich habe, besteht darin, eine Benutzersitzung über mehrere Aktivitäten hinweg aufrechtzuerhalten und dann die Sitzung in einer HttpClient -Zone einmal abzurufen. 

Ich möchte dies "richtig" tun, der empfohlene Ansatz scheint zu sein, CookieManager zu verwenden. Ich hatte jedoch Probleme damit - ich kann anscheinend nicht den "richtigen" Weg finden, ein Cookie aus dem CookieManager zu nehmen und es in einer späteren Instanziierung von HttpClient separat zu verwenden Aktivitäten.

Bei Verwendung eines CookieManager kann ich das Cookie speichern und das Cookie ist dann in anderen Aktivitäten im Gültigkeitsbereich (siehe Code-Schnipsel 2). Ich habe nicht gefunden, wie ich dies später verwenden kann (siehe Code-Snippet 3), wenn Sie eine Seite anfordern.

Genug geredet, hier ist ein Code. Zuerst meine Login-Aktion und Cookie-Speicherung: 

private OnClickListener loginActionListener = new OnClickListener() 
{
    public void onClick(View v) 
    {
        EditText usernameTextView = (EditText) findViewById(R.id.Username);
        EditText passwordTextView = (EditText) findViewById(R.id.Password);
        String username = usernameTextView.getText().toString();
        String password = passwordTextView.getText().toString();

        try {
            HttpPost postMethod = new HttpPost(URI);                
            HttpParams params   = new BasicHttpParams();

            params.setParameter("mode", "login");
            params.setParameter("autologin", true);
            params.setParameter("username", username);
            params.setParameter("password", password);
            postMethod.setParams(params);

            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpResponse response        = httpClient.execute(postMethod);
            List<Cookie> cookies = httpClient.getCookieStore().getCookies();

            if(cookies != null)
            {
                for(Cookie cookie : cookies)
                {
                    String cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();                        
                    CookieManager.getInstance().setCookie(cookie.getDomain(), cookieString);  
                }
            }
            CookieSyncManager.getInstance().sync();

            Intent intent = new Intent(v.getContext(), IndexAction.class);
            startActivity(intent);
    } catch (Exception e) {...}
}

Die Startaktivität, die entscheidet, ob sich der Benutzer anmelden oder zum Index wechseln soll, befindet sich unten. An diesem Code können Sie erkennen, dass das Cookie im Gültigkeitsbereich liegt und gelesen werden kann: 

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    CookieSyncManager.createInstance(this);

    if(CookieManager.getInstance().getCookie(URI) == null)
    {
        Intent intent = new Intent(this, LoginAction.class);
        startActivity(intent);
    }
    else
    {
        Intent intent = new Intent(this, IndexAction.class);
        startActivity(intent);
    }
}

Ich hoffe jedoch, dass Sie aus meinem Code die Indexseite lesen können, was ich vermisse: 

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    CookieSyncManager.createInstance(this);

    try
    {
            HttpGet getMethod = new HttpGet(URI_INDEX);  

            HttpParams params   = new BasicHttpParams();                        
            HttpConnectionParams.setConnectionTimeout(params, 30000);
            HttpConnectionParams.setSoTimeout(params, 30000);

            // This code results in a ClassCastException, I'm assuming i've found a red herring with this solution.
            // HttpContext localContext = new BasicHttpContext();    
            // localContext.setAttribute(ClientContext.COOKIE_STORE, CookieManager.getInstance().getCookie(URI));

            DefaultHttpClient httpClient = new DefaultHttpClient(params);
            HttpResponse response        = httpClient.execute(getMethod);

            if(response.getStatusLine().getStatusCode() > 299 && response.getStatusLine().getStatusCode() < 400)
            {
                // Not logged in doesn't give a redirect response. Very annoying.
            }

            final char[] buffer = new char[0x10000];
            StringBuilder out = new StringBuilder();
            Reader in = new InputStreamReader(response.getEntity().getContent(), "UTF-8");
            int read = 0;
            while (read>=0)
            {
              read = in.read(buffer, 0, buffer.length);
              if (read>0) {
                out.append(buffer, 0, read);
              }
            }

            String returnString = out.toString();
    } catch (ClientProtocolException e) {...}
}

Das HttpClient auf execute(getMethod) verwendet das Cookie nicht (dies wurde im Debug doppelt geprüft), um die Seite zurückzuziehen. Es wäre toll, wenn jemand dieses Loch meines Wissens füllen könnte.

Danke im Voraus.

EDIT

Wenn der kommentierte Code wieder hinzugefügt wird (mit der httpClient.execute(getMethod)-Methode in httpClient.execute(getMethod, localContext)), wird diese strack-Ablaufverfolgung erzeugt. Angenommen, ich fülle das Attribut ClientContext.COOKIE_STORE mit einem CookieString und nicht einem CookieStore:

*org.Apache.http.client.protocol.RequestAddCookies.process(RequestAddCookies.Java:88), org.Apache.http.protocol.BasicHttpProcessor.process(BasicHttpProcessor.Java:290), org.Apache.http.protocol.HttpRequestExecutor.preProcess(HttpRequestExecutor.Java:160), org.Apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.Java:401)
org.Apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.Java:555), org.Apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.Java:487), 
com.testapp.site.name.IndexAction.onCreate(IndexAction.Java:47), 
Android.app.Instrumentation.callActivityOnCreate(Instrumentation.Java:1047), 
Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:1611), 
Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:1663), 
Android.app.ActivityThread.access$1500(ActivityThread.Java:117), 
Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:931), 
Android.os.Handler.dispatchMessage(Handler.Java:99), 
Android.os.Looper.loop(Looper.Java:123), 
Android.app.ActivityThread.main(ActivityThread.Java:3683), 
Java.lang.reflect.Method.invokeNative(Native Method), 
Java.lang.reflect.Method.invoke(Method.Java:507), 
com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:839), 
com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:597), 
dalvik.system.NativeStart.main(Native Method)*
26
Graeme

(Wie versprochen, eine Lösung für dieses Problem. Ich mag es immer noch nicht und fühle mich, als würde ich die "richtige" Vorgehensweise verpassen, aber es funktioniert.)

Sie können die CookieManager verwenden, um Ihre Cookies zu registrieren (und diese Cookies daher zwischen Apps bereitzustellen) mit dem folgenden Code:

Cookies in der CookieManager speichern:

List<Cookie> cookies = httpClient.getCookieStore().getCookies();

if(cookies != null)
{
    for(Cookie cookie : cookies)
    {
        String cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();                        
        CookieManager.getInstance().setCookie(cookie.getDomain(), cookieString);  
    }
}
CookieSyncManager.getInstance().sync();

Überprüfung auf Cookies in der angegebenen Domain: if(CookieManager.getInstance().getCookie(URI_FOR_DOMAIN)

So rekonstruieren Sie Werte für HttpClient:

DefaultHttpClient httpClient = new DefaultHttpClient(params);
String[] keyValueSets = CookieManager.getInstance().getCookie(URI_FOR_DOMAIN).split(";");
for(String cookie : keyValueSets)
{
    String[] keyValue = cookie.split("=");
    String key = keyValue[0];
    String value = "";
    if(keyValue.length>1) value = keyValue[1];
    httpClient.getCookieStore().addCookie(new BasicClientCookie(key, value));
}
10
Graeme

CookieManager wird vom internen HTTP-Client von Java verwendet. Es hat nichts mit Apache HttpClient zu tun. 

In Ihrem Code erstellen Sie immer für jede Anforderung eine neue Instanz von HttpClient und somit eine neue CookieStore-Instanz, die offensichtlich zusammen mit allen gespeicherten Cookies Müll sammelt, sobald diese HttpClient-Instanz ihren Gültigkeitsbereich verlässt. 

Sie sollten entweder

(1) Dieselbe Instanz von HttpClientfür alle logisch zusammenhängenden HTTP-Anforderungen erneut verwenden und für alle logisch zusammenhängenden Threads freigeben (dies ist die empfohlene Methode für die Verwendung von Apache HttpClient).

(2) oder zumindest die gleiche Instanz von CookieStorezwischen logisch verwandten Threads gemeinsam nutzen

(3) oder, wenn Sie darauf bestehen, CookieManager zum Speichern all Ihrer Cookies zu verwenden, erstellen Sie eine benutzerdefinierte CookieStore-Implementierung, die von CookieManagerunterstützt wird.

23
oleg

In meinem Anwendungsserver möchte ich dieselbe Sitzung mit den gleichen Cookies verwenden ... Nach ein paar Stunden "googeln" und schmerzhaften Kopfschmerzen habe ich Cookies in SharedPreference gespeichert oder einfach ein Objekt eingefügt und DefaultHttpClient mit denselben Cookies erneut gesetzt ... onDestroy entfernt einfach SharedPreferences ... das ist alles:

  1. Kopieren Sie zuerst die Klasse SerializableCookie in Ihr Paket: SerializableCookie

Schauen Sie sich das folgende Beispiel an:

public class NodeServerTask extends AsyncTask<Void, Void, String> {
private DefaultHttpClient client;


protected String doInBackground(Void... params) {
  HttpPost httpPost = new HttpPost(url);
    List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
    urlParameters.add(nameValuePair);
    try {
        httpPost.setEntity(new UrlEncodedFormEntity(urlParameters));
        List<Cookie> cookies = loadSharedPreferencesCookie();
        if (cookies!=null){
            CookieStore cookieStore = new BasicCookieStore();
            for (int i=0; i<cookies.size(); i++)
                cookieStore.addCookie(cookies.get(i));
            client.setCookieStore(cookieStore);
        }
        HttpResponse response = client.execute(httpPost);
        cookies = client.getCookieStore().getCookies();

        saveSharedPreferencesCookies(cookies);

// zwei Methoden zum Speichern und Laden von Cookies ...

 private void saveSharedPreferencesCookies(List<Cookie> cookies) {
    SerializableCookie[] serializableCookies = new SerializableCookie[cookies.size()];
    for (int i=0;i<cookies.size();i++){
        SerializableCookie serializableCookie = new SerializableCookie(cookies.get(i));
        serializableCookies[i] = serializableCookie;
    }
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor = preferences.edit();
    ObjectOutputStream objectOutput;
    ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
    try {
        objectOutput = new ObjectOutputStream(arrayOutputStream);


        objectOutput.writeObject(serializableCookies);
        byte[] data = arrayOutputStream.toByteArray();
        objectOutput.close();
        arrayOutputStream.close();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Base64OutputStream b64 = new Base64OutputStream(out, Base64.DEFAULT);
        b64.write(data);
        b64.close();
        out.close();

        editor.putString("cookies", new String(out.toByteArray()));
        editor.apply();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private List<Cookie> loadSharedPreferencesCookie() {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    byte[] bytes = preferences.getString("cookies", "{}").getBytes();
    if (bytes.length == 0 || bytes.length==2)
        return null;
    ByteArrayInputStream byteArray = new ByteArrayInputStream(bytes);
    Base64InputStream base64InputStream = new Base64InputStream(byteArray, Base64.DEFAULT);
    ObjectInputStream in;
    List<Cookie> cookies = new ArrayList<Cookie>();
    SerializableCookie[] serializableCookies;
    try {
        in = new ObjectInputStream(base64InputStream);
        serializableCookies = (SerializableCookie[]) in.readObject();
        for (int i=0;i<serializableCookies.length; i++){
            Cookie cookie = serializableCookies[i].getCookie();
            cookies.add(cookie);
        }
        return cookies;
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}

Google Glück 

Ich hatte das gleiche Problem. Da ich Volley und nicht direkt HTTPClient verwende, schien Singleton für HTTPClient nicht die richtige Lösung zu sein. Mit der gleichen Idee habe ich einfach den CookieManager in meiner Anwendung Singleton gespeichert. Wenn also App meine Anwendung Singleton ist, dann füge ich in onCreate () jeder Aktivität Folgendes hinzu:

    if (app.cookieManager == null) {
        app.cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ALL);
    }
    CookieHandler.setDefault(app.cookieManager);

Um dies noch besser zu machen, sind alle meine Aktivitäten Unterklassen von MyAppActivity. Ich muss sie also nur in onCreate for MyAppActivity eintragen und dann erben alle meine Aktivitäten diese Funktionalität. Jetzt verwenden alle meine Aktivitäten den gleichen Cookie-Manager, und meine Webservice-Sitzung wird von allen Aktivitäten geteilt. Einfach und es funktioniert super.

1
Daniel Burton

Ich denke, eine der besten Sachen ist, Singleton Pattern auf Ihren HTTPClient anzuwenden, so dass Sie nur eine Instanz haben!

import org.Apache.http.client.HttpClient;
import org.Apache.http.impl.client.DefaultHttpClient;

public class myHttpClient {
    private static HttpClient mClient;
    private myHttpClient() {};
    public static HttpClient getInstance() {
        if(mClient==null)
            mClient = new DefaultHttpClient();
        return mClient;
    }
}
0
Antonio Calì