Cookie 是 Web 維持會話狀態的標準機制,但 Java ME (MIDP) 平台原生不支援。開發者常被迫使用 URL 重寫,操作繁瑣。本文解析 Cookie 原理,並示範如何在 Java ME 上完整實作:獲取 → 解析儲存 → 發送 三步驟。
Set-Cookie 中發送 Cookie (名稱=值; 屬性...)。Domain、Path、Expires 等屬性。Cookie 發送。HttpConnection 可透過 getHeaderField(int index) 遍歷標頭。注意:一個回應可能包含多個 Set-Cookie 標頭,需迴圈讀取。
String cookieHeader = null;
String key;
int i = 0;
while ((key = conn.getHeaderFieldKey(i)) != null) {
if ("Set-Cookie".equalsIgnoreCase(key) || "Set-Cookie2".equalsIgnoreCase(key)) {
cookieHeader = conn.getHeaderField(i);
saveCookie(cookieHeader, url);
}
i++;
}
定義 Cookie JavaBean 封裝屬性,並實作序列化以便存入 RMS (Record Management System)。
public class Cookie implements Serializable {
private String name, value, path;
private long expire; // 0 表 session cookie
// getter/setter 略
/** 解析 Set-Cookie 字串 */
public static Cookie parse(String header, String requestUri) {
Cookie c = new Cookie();
StringTokenizer st = new StringTokenizer(header, ";");
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
int eq = token.indexOf('=');
if (eq == -1) continue; // secure, httponly 等無值屬性
String n = token.substring(0, eq);
String v = token.substring(eq + 1);
if ("path".equalsIgnoreCase(n)) c.setPath(v);
else if ("expires".equalsIgnoreCase(n)) c.setExpire(parseDate(v));
else if ("domain".equalsIgnoreCase(n)) { /* 可選驗證 */ }
else { c.setName(n); c.setValue(v); }
}
if (c.getPath().isEmpty()) c.setPath(requestUri); // 預設路徑
return c;
}
/** 判斷是否過期 */
public boolean isExpired() {
return expire > 0 && expire < System.currentTimeMillis();
}
}
儲存策略:持久 Cookie 寫入 RMS;Session Cookie 僅存記憶體 Map,中途銷毀即可。
發送請求前,從 RMS 與記憶體撈取符合 Domain/Path 且未過期的 Cookie,組裝成 name1=value1; name2=value2 格式,設入請求屬性 Cookie。
String cookieStr = collectCookies(url); // 實作匹配邏輯
if (cookieStr != null) {
conn.setRequestProperty("Cookie", cookieStr);
}
《Java ME 核心技術與最佳實踐》書中提供的 httpme 網路框架已內建完整 Cookie 管理,可直接參考使用。
在 Java ME 手動實作 Cookie 雖需處理標頭解析、RMS 儲存、Domain/Path 匹配等細節,但能讓 MIDlet 像瀏覽器一樣自然維持會話狀態,大幅簡化伺服端交互邏輯。