使用HttpClient时在活动中使用Cookie

Gra*_*eme 26 java cookies android httpclient

我正在尝试一个简单的应用程序来阅读网站的HTML,并转换它以在Android中创建一个易于阅读的UI(这是一个学习android的exersize,而不是一个可用的应用程序).我遇到的问题是跨活动持久存在用户会话,然后在HttpClient一次召回时使用会话.

我想"正确地"这样做,推荐的方法似乎是使用CookieManager.然而,我遇到了这方面的问题 - 我似乎无法找到"正确"的方式来Cookie从一个单独的活动中CookieManager稍后实例化中使用它HttpClient.

当使用CookieManager我可以保存CookieCookie随后在其他活动(见代码段2)的范围.我在请求页面时没有找到如何使用它(请参阅代码片段3).

够了,这里有一些代码.首先我的登录操作和Cookie存储:

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) {...}
}
Run Code Online (Sandbox Code Playgroud)

启动Activity决定是否让用户登录或转到索引,如下所示.您可以从此代码中看到cookie在范围内并且可以读取:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是从我的代码中读取索引页面,我希望你可以建议我缺少的东西:

@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) {...}
}
Run Code Online (Sandbox Code Playgroud)

HttpClientexecute(getMethod)未使用的Cookie(调试双重检查这一点)拉回来的页面.如果有人能够在我的知识中填补这个漏洞,那将是很棒的.

提前致谢.

编辑

当重新添加注释代码时(httpClient.execute(getMethod)方法更改为httpClient.execute(getMethod, localContext)),会生成此strack跟踪 - 假设我正在ClientContext.COOKIE_STORE使用a 填充属性Cookie String而不是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)*
Run Code Online (Sandbox Code Playgroud)

ok2*_*k2c 23

CookieManager由Java的内部HTTP客户端使用.它与Apache HttpClient无关.

在您的代码中,您总是为每个请求创建一个新实例,HttpClient因此创建一个新CookieStore实例,当HttpClient实例超出范围时,显然会收集垃圾以及存储在其中的所有cookie .

你也应该

(1)对所有逻辑相关的HTTP请求重用相同的实例,HttpClient并在所有逻辑相关的线程之间共享(这是使用Apache HttpClient的推荐方法)

(2)或者至少在逻辑上相关的线程之间共享相同的实例CookieStore

(3)或者,如果您坚持使用CookieManager存储所有cookie,请创建一个CookieStore支持的自定义实现CookieManager


Gra*_*eme 10

(正如所承诺的那样解决方案.我仍然不喜欢它,并且觉得我错过了"正确"这样做的方式,但它确实有效.)

您可以使用CookieManager以下代码注册您的cookie(并因此在应用程序之间提供这些cookie):

将cookie保存到CookieManager:

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();
Run Code Online (Sandbox Code Playgroud)

检查指定域上的cookie: if(CookieManager.getInstance().getCookie(URI_FOR_DOMAIN)

要重建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));
}
Run Code Online (Sandbox Code Playgroud)

  • 重要的是还要设置新的BasicClientCookie(键,值)的域,以便更好地像BasicClientCookie c = new BasicClientCookie(key,value); c.setDomain(URI_FOR_DOMAIN); httpClient.getCookieStore()的addCookie(c)中. (2认同)