首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

Java ME 實現 Cookie 機制:原理解析與完整代碼實現

     編輯:J2ME

彌補 Java ME 缺失的 Cookie 支持:從原理到 RMS 持久化

Web 應用依賴 Cookie 維持會話狀態,但 Java ME (MIDP) 標準庫未提供 Cookie 支持。本文深入分析 Cookie 工作原理,並給出完整的客戶端實現方案:解析 Set-Cookie 頭、RMS 持久化存儲、請求時自動附帶 Cookie 頭,實現與服務端的有狀態交互。

Cookie 工作原理回顧

  1. 服務端響應頭 Set-Cookie: name=value; Path=/; Domain=example.com; Expires=...
  2. 客戶端解析並存儲(內存/持久化)。
  3. 後續請求匹配 Domain + Path,符合則發送 Cookie: name=value。
  4. 過期時間到期或會話結束(無 Expires)自動清除。

三步實現核心流程

1. 獲取 Cookie:遍歷響應頭

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

2. 解析與存儲:Java Bean + RMS

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
}

3. 發送 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);
}

關鍵細節與避坑指南

  • Domain 匹配:.google.com 匹配 mail.google.com,但不匹配 google.com.hk。需按 RFC 2965 規則實現尾匹配。
  • Path 匹配:Cookie Path 必須是請求 URI 的前綴(如 /app/ 匹配 /app/login)。
  • 過期時間解析:HTTP 日期格式固定,可用 SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US) 解析(注意 J2ME 無 Locale,需手寫解析或用第三方庫)。
  • RMS 存儲限額:Cookie 體積小,極少觸及配額。定期清理過期記錄。
  • 安全性:不支持 Secure/HttpOnly 標誌屬性可忽略,但切勿在明文 HTTP 傳輸敏感 Cookie。

參考資源

《Java ME 核心技巧與最佳實踐》書中提供的 httpme 網絡框架已內置完整 Cookie 實現,生產項目建議直接集成該框架而非重複造輪子。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved