使用HttpClient时在活动中使用Cookie

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

我想“正确地”这样做,推荐的方法似乎是使用CookieManager 。 但是我遇到了这个问题 – 我似乎无法find从CookieManager获取Cookie的“正确”方法,并在以后的单独活动中将HttpClient实例化。

当使用CookieManager我可以保存Cookie ,然后Cookie就在其他活动的范围内(参见代码片段2)。 我在请求页面时没有find如何使用它(请参阅代码片段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 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) {...} } 

启动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); } } 

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

 @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() =0) { read = in.read(buffer, 0, buffer.length); if (read>0) { out.append(buffer, 0, read); } } String returnString = out.toString(); } catch (ClientProtocolException e) {...} } 

execute(getMethod)HttpClient execute(getMethod)没有使用Cookie(在调试中双重检查)以撤回页面。 如果有人能够在我的知识中填补这个漏洞,那将是很棒的。

提前致谢。

编辑

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

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

在您的代码中,您总是为每个请求创建一个新的HttpClient实例,从而创建一个新的CookieStore实例,一旦HttpClient实例超出范围,它就会立即收集垃圾以及存储在其中的所有cookie。

你也应该

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

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

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

(正如承诺的解决方案。我仍然不喜欢它,并且觉得我错过了“正确”这样做的方式,但是,它有效。)

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

将Cookie保存到CookieManager

 List 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(); 

检查指定域上的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)); } 

在我的应用程序服务器想要使用相同的会话与相同的cookie …经过几个小时的“谷歌搜索”和痛苦的头痛我刚刚将cookie保存到SharedPreference或只是放入一些对象并再次使用相同的cookie设置DefaultHttpClient … onDestroy刚刚删除SharedPreferences ……就是这样:

  1. 首先将SerializableCookie类复制到您的包: SerializableCookie

看下面的例子:

 public class NodeServerTask extends AsyncTask { private DefaultHttpClient client; protected String doInBackground(Void... params) { HttpPost httpPost = new HttpPost(url); List urlParameters = new ArrayList(); urlParameters.add(nameValuePair); try { httpPost.setEntity(new UrlEncodedFormEntity(urlParameters)); List cookies = loadSharedPreferencesCookie(); if (cookies!=null){ CookieStore cookieStore = new BasicCookieStore(); for (int i=0; i 

//两种保存和加载cookie的方法......

  private void saveSharedPreferencesCookies(List cookies) { SerializableCookie[] serializableCookies = new SerializableCookie[cookies.size()]; for (int i=0;i 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 cookies = new ArrayList(); SerializableCookie[] serializableCookies; try { in = new ObjectInputStream(base64InputStream); serializableCookies = (SerializableCookie[]) in.readObject(); for (int i=0;i 

谷歌运气

我有同样的问题。 由于我直接使用Volley而不是HTTPClient,因此用于HTTPClient的Singleton似乎不是正确的解决方案。 但是使用相同的想法我只是在我的应用程序单例中保存了CookieManager。 因此,如果app是我的应用程序单例,那么在每个活动的onCreate()中我添加:

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

为了使这更好,我的所有活动都是MyAppActivity的子类,因此我所要做的就是将它放在onCreate for MyAppActivity中,然后我的所有活动都inheritance了这个function。 现在我的所有活动都使用相同的cookie管理器,所有活动都共享我的Web服务会话。 简单,效果很好。

我想最好的事情之一是将Singleton Pattern应用于您的HTTPClient,因此您只有一个实例!

 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; } } 

cookie存储的一个很好的解决方案是遵循ThreadLocal模式,以避免随机存储cookie。

这将有助于保持一个唯一的CookieStore。 有关此模式的更多说明,您可以按照此有用的链接。

http://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/

干杯