在最近寫的一個Android中需要請求web伺服器中的資料,有一個登入Activity,登入後會到MainActivity,這中間登入和MainActivity都需要請求php的jsonapi,所以要在網路請求中保持session的,研究了好半天才搞定。其實sesion在瀏覽器和web伺服器直接是通過一個叫做name為sessionid的cookie來傳遞的,所以只要在每次資料請求時保持sessionid是同一個不變就可以用到web的session了,做法是第一次資料請求時就擷取sessionid的值並儲存在一個靜態變數中,然後在第二次請求資料的時候要將這個sessionid一併放在Cookie中發給伺服器,伺服器則是通過這個sessionid來識別究竟是那個用戶端在請求資料的,在php中這個sessionid的名字叫做PHPSESSID。下面貼下代碼
複製代碼 代碼如下:import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
public class MyHttpClient implements InetConfig {
private DefaultHttpClient httpClient;
private HttpPost httpPost;
private HttpEntity httpEntity;
private HttpResponse httpResponse;
public static String PHPSESSID = null;
public LVHttpClient() {
}
public String executeRequest(String path, List<NameValuePair> params) {
String ret = "none";
try {
this.httpPost = new HttpPost(BASEPATH + path);
httpEntity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
httpPost.setEntity(httpEntity);
//第一次一般是還未被賦值,若有值則將SessionId發給伺服器
if(null != PHPSESSID){
httpPost.setHeader("Cookie", "PHPSESSID=" + PHPSESSID);
}
httpClient = new DefaultHttpClient();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
httpResponse = httpClient.execute(httpPost);
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = httpResponse.getEntity();
ret = EntityUtils.toString(entity);
CookieStore mCookieStore = httpClient.getCookieStore();
List<Cookie> cookies = mCookieStore.getCookies();
for (int i = 0; i < cookies.size(); i++) {
//這裡是讀取Cookie['PHPSESSID']的值存在靜態變數中,保證每次都是同一個值
if ("PHPSESSID".equals(cookies.get(i).getName())) {
PHPSESSID = cookies.get(i).getValue();
break;
}
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return ret;
}
}
其實web的原理都是一樣的,基於http協議的,那麼如果網站不是php做的話,那個叫做Sessionid的Cookie可能叫做別的了,就不是PHPSESSID了,而是叫做別的名字了,這個可能要具體情況去查了。
其實不只是Android程式,其他任何程式需要這麼用的時候只需要在http協議請求header裡頭加上發送相應的SessionId就可以了。剛剛這種方法是可以協助理解sessionid的,其實還有一種方法如果更通用的話,就可以將剛剛所有的Cookie每次都發回到伺服器端,也就可以解決session保持的問題了,只是這樣可能會稍微大些網路流量開銷而已。
這裡看到一個SessionId的本質,順便mark一下。
SessionID的本質
一、用戶端用cookie儲存了sessionID
用戶端用cookie儲存了sessionID,當我們請求伺服器的時候,會把這個sessionID一起發給伺服器,伺服器會到記憶體中搜尋對應的sessionID,如果找到了對應的 sessionID,說明我們處於登入狀態,有相應的許可權;如果沒有找到對應的sessionID,這說明:要麼是我們把瀏覽器關掉了(後面會說明為什 麼),要麼session逾時了(沒有請求伺服器超過20分鐘),session被伺服器清除了,則伺服器會給你分配一個新的sessionID。你得重 新登入並把這個新的sessionID儲存在cookie中。
在沒有把瀏覽器關掉的時候(這個時候假如已經把sessionID儲存在cookie中了)這個sessionID會一直儲存在瀏覽器中,每次請求的時候都會把這個sessionID提交到伺服器,所以伺服器認為我們是登入的;當然,如果太長時間沒有請求伺服器,伺服器會認為我們已經所以把瀏覽器關掉了,這個時候伺服器會把該sessionID從記憶體中清除掉,這個時候如果我們再去請求伺服器,sessionID已經不存在了,所以伺服器並沒有在記憶體中找到對應的 sessionID,所以會再產生一個新的sessionID,這個時候一般我們又要再登入一次。
二、用戶端沒有用cookie儲存sessionID
這 個時候如果我們請求伺服器,因為沒有提交sessionID上來,伺服器會認為你是一個全新的請求,伺服器會給你分配一個新的sessionID,這就是 為什麼我們每次開啟一個新的瀏覽器的時候(無論之前我們有沒有登入過)都會產生一個新的sessionID(或者是會讓我們重新登入)。
當我們一旦把瀏覽器關掉後,再開啟瀏覽器再請求該頁面,它會讓我們登入,這是為什嗎?我們明明已經登入了,而且還沒有逾時,sessionID肯定還在服 務器上的,為什麼現在我們又要再一次登入呢?這是因為我們關掉瀏覽再請求的時候,我們提交的資訊沒有把剛才的sessionID一起提交到伺服器,所以伺服器不知道我們是同一個人,所以這時伺服器又為我們分配一個新的sessionID,打個比方:瀏覽器就好像一個要去銀行開戶的人,而伺服器就好比銀行, 這個要去銀行開戶的人這個時候顯然沒有帳號(sessionID),所以到銀行後,銀行工作人員問有沒有帳號,他說沒有,這個時候銀行就會為他開通一個帳 號。所以可以這麼說,每次開啟一個新的瀏覽器去請求的一個頁面的時候,伺服器都會認為,這是一個新的請求,他為你分配一個新的sessionID。