Web 應用依賴 Cookie 維持會話狀態,但 Java ME (MIDP) 標準庫未提供 Cookie 支持。本文深入分析 Cookie 工作原理,並給出完整的客戶端實現方案:解析 Set-Cookie 頭、RMS 持久化存儲、請求時自動附帶 Cookie 頭,實現與服務端的有狀態交互。
Set-Cookie: name=value; Path=/; Domain=example.com; Expires=...Cookie: name=value。String SET_COOKIE = "Set-Cookie";
String SESSION_ID = "SessionID"; // 部分服務器用此頭
int i = 0;
String key;
while ((key = conn.getHeaderFieldKey(i)) != null) {
if (SET_COOKIE.equalsIgnoreCase(key) || SESSION_ID.equalsIgnoreCase(key)) {
String cookieStr = conn.getHeaderField(i);
saveCookie(cookieStr, url);
}
i++;
}
public class Cookie implements Serializable {
private String name, value, path;
private long expire; // 0 = session cookie
public static final long SESSION_COOKIE = 0;
// getters/setters/serialize/deserialize 略
// 解析 "name=value; Path=/; Expires=Wed, 21 Oct 2015 07:28:00 GMT"
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;
}
// 會話級 Cookie 只存內存 Map,持久 Cookie 存 RMS
// RMS 記錄存結構:RecordStore "Cookies",每條記錄 = 序列化後的 Cookie
}
private String collectCookies(String url) {
StringBuilder sb = new StringBuilder();
// 1. 從內存會話 Map 讀取
// 2. 從 RMS 讀取並過濾未過期、Domain/Path 匹配
// 3. 拼接 "name1=value1; name2=value2"
return sb.length() > 0 ? sb.toString() : null;
}
// 發送請求前
String cookieHeader = collectCookies(targetUrl);
if (cookieHeader != null) {
conn.setRequestProperty("Cookie", cookieHeader);
}
.google.com 匹配 mail.google.com,但不匹配 google.com.hk。需按 RFC 2965 規則實現尾匹配。/app/ 匹配 /app/login)。SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US) 解析(注意 J2ME 無 Locale,需手寫解析或用第三方庫)。Secure/HttpOnly 標誌屬性可忽略,但切勿在明文 HTTP 傳輸敏感 Cookie。《Java ME 核心技巧與最佳實踐》書中提供的 httpme 網絡框架已內置完整 Cookie 實現,生產項目建議直接集成該框架而非重複造輪子。