在解析網(wǎng)頁(yè)信息的時(shí)候,需要登錄后才能訪問,所以使用httpclient模擬登錄,然后把cookie保存下來(lái),以供下一次訪問使用,這時(shí)就需要持久化cookie中的內(nèi)容。
在之前先科普一下基礎(chǔ)知識(shí):
什么是Cookies?
Cookies是一些小文件,它們被創(chuàng)建在客戶端的系統(tǒng)里,或者被創(chuàng)建在客戶端瀏覽器的內(nèi)存中(如果是臨時(shí)性的話)。用它可以實(shí)現(xiàn)狀態(tài)管理的功能。我們可以存儲(chǔ)一些少量信息到可以短的系統(tǒng)上,以便在需要的時(shí)候使用。最有趣的事情是,它是對(duì)用戶透明的。在你的web應(yīng)用程序中,你可以到處使用它,它極其得簡(jiǎn)單。Cookies是以文本形式存儲(chǔ)的。如果一個(gè)web應(yīng)用程序使用cookies,那么服務(wù)器負(fù)責(zé)發(fā)送cookies,客戶端瀏覽器將存儲(chǔ)它。瀏覽器在下次請(qǐng)求頁(yè)面的時(shí)候,會(huì)返回cookies給服務(wù)器。最常用的例子是,使用一個(gè)cookie來(lái)存儲(chǔ)用戶信息,用戶的喜好,“記住密碼”操作等。Cookies有許多優(yōu)點(diǎn),當(dāng)然也有許多缺點(diǎn)。我將在接下來(lái)講述。
Cookies是如何創(chuàng)建的?
當(dāng)一個(gè)客戶端向服務(wù)器發(fā)出請(qǐng)求,服務(wù)器發(fā)送cookies給客戶端。而相同的cookies可以被后續(xù)的請(qǐng)求使用。例如,如果codeproject.com將Session ID作為cookies存儲(chǔ)。當(dāng)一個(gè)客戶端首次向web服務(wù)器請(qǐng)求頁(yè)面,服務(wù)器生成Session ID,并將其作為cookies發(fā)送往客戶端。
現(xiàn)在,所有來(lái)自相同客戶端的后續(xù)請(qǐng)求,它將使用來(lái)自cookies的Session ID,就像下面這幅圖片展示的那樣。
瀏覽器和web服務(wù)器以交換cookies信息來(lái)作為響應(yīng)。對(duì)不同的站點(diǎn),瀏覽器會(huì)維護(hù)不同的cookies。如果一個(gè)頁(yè)面需要cookies中的信息,當(dāng)某個(gè)URL被“點(diǎn)擊”,首先瀏覽器將搜索本地系統(tǒng)的cookies的信息,然后才轉(zhuǎn)向服務(wù)器來(lái)獲得信息。
Cookies的優(yōu)勢(shì)
下面是使用cookies的主要優(yōu)勢(shì):
(1) 實(shí)現(xiàn)和使用都是非常簡(jiǎn)單的
(2) 由瀏覽器來(lái)負(fù)責(zé)維護(hù)發(fā)送過(guò)來(lái)的數(shù)據(jù)(cookies內(nèi)容)
(3) 對(duì)來(lái)自多個(gè)站點(diǎn)的cookies來(lái)講,瀏覽器自動(dòng)管理它們
Cookies的劣勢(shì)
下面是cookies的主要劣勢(shì):
(1) 它以簡(jiǎn)單的文本格式來(lái)存儲(chǔ)數(shù)據(jù),所以它一點(diǎn)也不安全
(2) 對(duì)于cookies數(shù)據(jù),有大小限制(4kB)
(3) Cookies最大數(shù)目也有限制。主流瀏覽器提供將cookies的個(gè)數(shù)限制在20條。如果新cookies到來(lái),那么老的將被刪除。有些瀏覽器能支持到300條的cookies數(shù)。
(4) 我們需要配置瀏覽器,cookies將不能工作在瀏覽器配置的高安全級(jí)別環(huán)境下。
什么是持久化的和非持久化的Cookies
我們可以將cookies分成兩類:
(1) 持久化的cookies
(2) 非持久化的cookies
持久化的cookies:這可以被稱為永久性的cookies,它被存儲(chǔ)在客戶端的硬盤內(nèi),直到它們失效。持久化的cookies應(yīng)該被設(shè)置一個(gè)失效時(shí)間。有時(shí),它們會(huì)一直存在直到用戶刪除它們。持久化的cookies通常被用來(lái)為某個(gè)系統(tǒng)收集一個(gè)用戶的標(biāo)識(shí)信息。
非持久化cookies:也可以被稱之為臨時(shí)性的cookies。如果沒有定義失效時(shí)間,那么cookie將會(huì)被存儲(chǔ)在瀏覽器的內(nèi)存中。我上面展示的例子就是一個(gè)非持久的cookies。
修改一個(gè)持久化的cookies與一個(gè)非持久化的cookies并沒有什么不同。它們唯一的區(qū)別是——持久化的cookies有一個(gè)失效時(shí)間的設(shè)置。
Cookie持久化
HttpClient可以和任意物理表示的實(shí)現(xiàn)了CookieStore接口的持久化cookie存儲(chǔ)一起使用。默認(rèn)的CookieStore實(shí)現(xiàn)稱為BasicClientCookie,這是憑借java.util.ArrayList的一個(gè)簡(jiǎn)單實(shí)現(xiàn)。在BasicClientCookie對(duì)象中存儲(chǔ)的cookie當(dāng)容器對(duì)象被垃圾回收機(jī)制回收時(shí)會(huì)丟失。如果需要,用戶可以提供更復(fù)雜的實(shí)現(xiàn)。
下載著重介紹在安卓中如何利用httpclient來(lái)實(shí)現(xiàn)對(duì)cookie的持久化操作:
一、請(qǐng)求網(wǎng)絡(luò)獲取cookie
先看一下下面的代碼:
1
2
3
4
5
|
DefaultHttpClient httpclient = new DefaultHttpClient(); HttpGet httpget = new HttpGet( "http://www.hlovey.com" ); HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); List<Cookie> cookies = httpclient.getCookieStore().getCookies(); |
Post模擬登錄
1
2
3
4
5
6
7
8
9
10
11
12
13
|
HttpPost httpPost = new HttpPost(url); List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add( new BasicNameValuePair( "id" , userid)); formparams.add( new BasicNameValuePair( "passwd" , passwd)); UrlEncodedFormEntity entity; try { entity = new UrlEncodedFormEntity(formparams, mobileSMTHEncoding); } catch (UnsupportedEncodingException e1) { return 3 ; } httpPost.setEntity(entity); httpPost.setHeader( "User-Agent" , userAgent); HttpResponse response = httpClient.execute(httpPost); |
二、保存cookie
保存cookie有兩種方式一種是數(shù)據(jù)庫(kù),另一種是SharedPreferences,其中http://www.jfrwli.cn/article/140423.htm是使用數(shù)據(jù)庫(kù)來(lái)保存的,這里我是使用SharedPreferences保存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
package com.smthbest.smth.util; import java.util.Locale; import android.content.Context; import android.content.SharedPreferences; import android.text.TextUtils; import android.util.Log; import org.apache.http.client.CookieStore; import org.apache.http.cookie.Cookie; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; ic class PersistentCookieStore implements CookieStore { private static final String LOG_TAG = "PersistentCookieStore" ; private static final String COOKIE_PREFS = "CookiePrefsFile" ; private static final String COOKIE_NAME_STORE = "names" ; private static final String COOKIE_NAME_PREFIX = "cookie_" ; private boolean omitNonPersistentCookies = false ; private final ConcurrentHashMap<String, Cookie> cookies; private final SharedPreferences cookiePrefs; /** * Construct a persistent cookie store. * * @param context Context to attach cookie store to */ public PersistentCookieStore(Context context) { cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0 ); cookies = new ConcurrentHashMap<String, Cookie>(); // Load any previously stored cookies into the store String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null ); if (storedCookieNames != null ) { String[] cookieNames = TextUtils.split(storedCookieNames, "," ); for (String name : cookieNames) { String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null ); if (encodedCookie != null ) { Cookie decodedCookie = decodeCookie(encodedCookie); if (decodedCookie != null ) { cookies.put(name, decodedCookie); } } } // Clear out expired cookies clearExpired( new Date()); } } @Override public void addCookie(Cookie cookie) { if (omitNonPersistentCookies && !cookie.isPersistent()) return ; String name = cookie.getName() + cookie.getDomain(); // Save cookie into local store, or remove if expired if (!cookie.isExpired( new Date())) { cookies.put(name, cookie); } else { cookies.remove(name); } // Save cookie into persistent store SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join( "," , cookies.keySet())); prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie( new SerializableCookie(cookie))); prefsWriter.commit(); } @Override public void clear() { // Clear cookies from persistent store SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); for (String name : cookies.keySet()) { prefsWriter.remove(COOKIE_NAME_PREFIX + name); } prefsWriter.remove(COOKIE_NAME_STORE); prefsWriter.commit(); // Clear cookies from local store cookies.clear(); } @Override public boolean clearExpired(Date date) { boolean clearedAny = false ; SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); for (ConcurrentHashMap.Entry<String, Cookie> entry : cookies.entrySet()) { String name = entry.getKey(); Cookie cookie = entry.getValue(); if (cookie.isExpired(date)) { // Clear cookies from local store cookies.remove(name); // Clear cookies from persistent store prefsWriter.remove(COOKIE_NAME_PREFIX + name); // We've cleared at least one clearedAny = true ; } } // Update names in persistent store if (clearedAny) { prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join( "," , cookies.keySet())); } prefsWriter.commit(); return clearedAny; } @Override public List<Cookie> getCookies() { return new ArrayList<Cookie>(cookies.values()); } /** * Will make PersistentCookieStore instance ignore Cookies, which are non-persistent by * signature (`Cookie.isPersistent`) * * @param omitNonPersistentCookies true if non-persistent cookies should be omited */ public void setOmitNonPersistentCookies( boolean omitNonPersistentCookies) { this .omitNonPersistentCookies = omitNonPersistentCookies; } /** * Non-standard helper method, to delete cookie * * @param cookie cookie to be removed */ public void deleteCookie(Cookie cookie) { String name = cookie.getName(); cookies.remove(name); SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.remove(COOKIE_NAME_PREFIX + name); prefsWriter.commit(); } /** * Serializes Cookie object into String * * @param cookie cookie to be encoded, can be null * @return cookie encoded as String */ protected String encodeCookie(SerializableCookie cookie) { if (cookie == null ) return null ; ByteArrayOutputStream os = new ByteArrayOutputStream(); try { ObjectOutputStream outputStream = new ObjectOutputStream(os); outputStream.writeObject(cookie); } catch (Exception e) { return null ; } return byteArrayToHexString(os.toByteArray()); } /** * Returns cookie decoded from cookie string * * @param cookieString string of cookie as returned from http request * @return decoded cookie or null if exception occured */ protected Cookie decodeCookie(String cookieString) { byte [] bytes = hexStringToByteArray(cookieString); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); Cookie cookie = null ; try { ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); cookie = ((SerializableCookie) objectInputStream.readObject()).getCookie(); } catch (Exception exception) { Log.d(LOG_TAG, "decodeCookie failed" , exception); } return cookie; } /** * Using some super basic byte array <-> hex conversions so we don't have to rely on any * large Base64 libraries. Can be overridden if you like! * * @param bytes byte array to be converted * @return string containing hex values */ protected String byteArrayToHexString( byte [] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2 ); for ( byte element : bytes) { int v = element & 0xff ; if (v < 16 ) { sb.append( '0' ); } sb.append(Integer.toHexString(v)); } return sb.toString().toUpperCase(Locale.US); } /** * Converts hex values from strings to byte arra * * @param hexString string of hex-encoded values * @return decoded byte array */ protected byte [] hexStringToByteArray(String hexString) { int len = hexString.length(); byte [] data = new byte [len / 2 ]; for ( int i = 0 ; i < len; i += 2 ) { data[i / 2 ] = ( byte ) ((Character.digit(hexString.charAt(i), 16 ) << 4 ) + Character.digit(hexString.charAt(i + 1 ), 16 )); } return data; } |
使用PersistentCookieStore來(lái)存儲(chǔ)cookie,首先最好把PersistentCookieStore放在Application獲取其他的地方,取得唯一實(shí)例,保存cookie是在登錄成功后,從下面代碼獲取保存。
1
2
3
4
5
|
PersistentCookieStore myCookieStore = App.getInstance().getPersistentCookieStore(); List<Cookie> cookies = httpClient.getCookieStore().getCookies(); for (Cookie cookie:cookies){ myCookieStore.addCookie(cookie); } |
三、cookie的使用
1
2
3
|
PersistentCookieStore cookieStore = new PersistentCookieStore(SmthBestApp.getInstance().getApplicationContext()); httpClient.setCookieStore(cookieStore); HttpResponse response = httpClient.execute(httpget); |
這樣就可以免再次登錄了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/shimiso/article/details/39033353