企業系統遷移期常面臨 **ASP.NET (UTF-8)** 與 **傳統 ASP (GB2312/Big5)** 共存,需共享登入狀態 (Cookie)。預設情況下:
統一雙方對中文 Cookie Value 的編碼格式為 GB2312 (或雙方協商的編碼),並在讀寫時顯式指定編碼。
// C# (ASP.NET)
public static void WriteCookie(string cookieName, string key, string value)
{
// 1. 取得 GB2312 編碼器
Encoding gb2312 = Encoding.GetEncoding("GB2312"); // 或 "CP936"
// 2. 使用 GB2312 進行 UrlEncode
string encodedValue = HttpUtility.UrlEncode(value, gb2312);
// 3. 寫入 Cookie
HttpContext.Current.Response.Cookies[cookieName][key] = encodedValue;
// 可選:設定 Domain/Path/Expires 確保跨應用程式存取
// HttpContext.Current.Response.Cookies[cookieName].Domain = ".example.com";
}
// C# (ASP.NET)
public static string ReadCookie(string cookieName, string key)
{
var cookie = HttpContext.Current.Request.Cookies[cookieName];
if (cookie == null || cookie[key] == null) return null;
string encodedValue = cookie[key];
// 1. 先用預設 (UTF-8) UrlDecode 一次 (因為 Request 會自動 UrlDecode 一次)
// 注意:ASP.NET Request 會自動對 Cookie Value 做 UrlDecode (預設 UTF-8)
// 所以我們拿到的已經是「UTF-8 解碼後的 GB2312 位元組序列轉字串」-> 亂碼字串
// 2. 將此亂碼字串還原為位元組 (用 ISO-8859-1 或 Default 反向)
// 3. 再用 GB2312 正確解碼
// 簡化版:直接用 GB2312 UrlDecode (ASP.NET 4.5+ HttpUtility 支援指定編碼解碼)
Encoding gb2312 = Encoding.GetEncoding("GB2312");
return HttpUtility.UrlDecode(encodedValue, gb2312);
// 若版本不支援,手動還原:
// byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(encodedValue);
// return gb2312.GetString(bytes);
}
' VBScript (Classic ASP)
' 寫入 - ASP 原生即為 GB2312 (系統代碼頁)
Response.Cookies(cookieName)(key) = Server.URLEncode(value) ' value 為 GB2312 字串
' 讀取
Dim val
val = Request.Cookies(cookieName)(key)
If Not IsEmpty(val) Then
val = Server.URLDecode(val) ' 解碼為 GB2312 字串
End If
<!-- web.config -->
<system.web>
<globalization requestEncoding="GB2312" responseEncoding="GB2312" fileEncoding="GB2312" />
</system.web>
缺點:影響整個應用程式的請求/回應/檔案讀寫編碼,可能導致資料庫存取、前端頁面、API 介接等全線亂碼,**強烈不建議** 除非整個專案純中文且無外部整合。
using System;
using System.Text;
using System.Web;
public static class CrossPlatformCookieHelper
{
// 協商編碼:GB2312 (相容 ASP) 或 UTF-8 (現代標準,需 ASP 端配合)
private static readonly Encoding _cookieEncoding = Encoding.GetEncoding("GB2312");
private const string CookieDomain = ".yourdomain.com"; // 設定共同根域名
/// 寫入跨平台相容 Cookie
public static void SetCookie(string name, string key, string value, DateTime? expires = null, string path = "/")
{
var cookie = new HttpCookie(name)
{
Domain = CookieDomain,
Path = path,
HttpOnly = true,
Secure = HttpContext.Current.Request.IsSecureConnection // HTTPS 時自動 Secure
};
if (expires.HasValue) cookie.Expires = expires.Value;
// 關鍵:使用協商編碼 UrlEncode
cookie[key] = HttpUtility.UrlEncode(value, _cookieEncoding);
HttpContext.Current.Response.Cookies.Set(cookie);
}
/// 讀取跨平台相容 Cookie
public static string GetCookie(string name, string key)
{
var cookie = HttpContext.Current.Request.Cookies[name];
if (cookie == null || cookie[key] == null) return null;
// 關鍵:使用協商編碼 UrlDecode
return HttpUtility.UrlDecode(cookie[key], _cookieEncoding);
}
/// 刪除 Cookie (跨平台通用)
public static void RemoveCookie(string name, string path = "/")
{
var cookie = new HttpCookie(name)
{
Domain = CookieDomain,
Path = path,
Expires = DateTime.Now.AddDays(-1),
Value = ""
};
HttpContext.Current.Response.Cookies.Set(cookie);
}
/// 清除所有 Cookie (含 Session)
public static void ClearAllCookies()
{
// 1. 清除 Request Cookies 集合 (避免迭代修改集合)
var keys = HttpContext.Current.Request.Cookies.AllKeys;
foreach (var key in keys)
{
RemoveCookie(key);
}
// 2. 明確清除 Response 集合
HttpContext.Current.Response.Cookies.Clear();
// 3. 終結 Session
HttpContext.Current.Session?.Abandon();
}
}
| 現象 | 原因 | 驗證/修正 |
|---|---|---|
| ASP.NET 寫入後 ASP 讀取亂碼 | ASP.NET 用 UTF-8 編碼,ASP 用 GB2312 解碼 | ASP.NET 強制用 GB2312 `UrlEncode` |
| ASP 寫入後 ASP.NET 顯示亂碼 | ASP.NET Request 自動用 UTF-8 UrlDecode | ASP.NET 用 GB2312 `UrlDecode` 手動修正 |
| 跨子域名無法共享 | Cookie Domain 未設定為共同根域名 | 雙方設 `Domain = ".example.com"` |
| HTTPS 下 Cookie 不傳送 | 未設 Secure 標記 / SameSite 政策 | 設 `Secure = true`,SameSite=Lax/None |
| 清除 Cookie 後 ASP 仍讀到舊值 | 未呼叫 `Response.Cookies.Clear()` 或路徑/域名不匹配 | 同 Domain/Path 設 Expires 為過去時間 + `Response.Cookies.Clear()` |
ASP.NET 與 ASP 中文 Cookie 互通的核心在於 **雙方協商統一編碼 (建議 GB2312)** 並在讀寫時 **顯式指定編碼**。提供的 `CrossPlatformCookieHelper` 可直接納入專案解決歷史包袱。長遠規劃應遷移至 Token + 共享 Session 架構,從根本消除編碼相容性問題。