Cookie 由伺服器設定(Set-Cookie 響應頭),瀏覽器自動攜帶(Cookie 請求頭)於後續請求。ASP.NET 封裝了完整的讀寫機制,本文追溯源碼級實現。
public HttpCookieCollection Cookies {
get { EnsureCookies(); return _cookies; }
}
internal HttpCookieCollection EnsureCookies() {
if (_cookies == null) {
_cookies = new HttpCookieCollection(null, false);
if (_wr != null) FillInCookiesCollection(_cookies, true);
if (HasTransitionedToWebSocketRequest) _cookies.MakeReadOnly();
}
return _cookies;
}
internal void FillInCookiesCollection(HttpCookieCollection cookieCollection, bool includeResponse) {
// 1. 從 HttpWorkerRequest 獲取原始 Cookie 字符串
String s = _wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderCookie);
// 2. 按分號分割解析每個 Cookie
// 格式: name=value; name2=value2; ...
// 支援子鍵: name=key1=val1&key2=val2
// 3. 處理 $Path、$Domain 等屬性前綴
// 4. 合併響應端已設定的 Cookie (includeResponse=true)
}
GetServerVariable("ALL_RAW") 獲取原始 HTTP 頭ISAPIWorkerRequestInProcForIIS7 → ... → HttpWorkerRequest解析 name=value 或 name=key1=val1&key2=val2 格式,填充 HttpCookie.Values 集合。
private void ValidateCookieCollection(HttpCookieCollection cc) {
// 預設啟用請求驗證,防 XSS 注入
// 呼叫 RequestValidator.Current.IsValidRequestString
// 支援粒度驗證:按需驗證而非全量驗證
}
Name/Value、Domain/Path、Expires、Secure/HttpOnly、Shareable(影響輸出緩存)_changed、_added、FromHeaderinternal HttpResponseHeader GetSetCookieHeader(HttpContext context) {
StringBuilder s = new StringBuilder();
s.Append(Name).Append('=');
// 值處理:支援多值集合
if (_multiValue != null) s.Append(_multiValue.ToString(false));
else if (_stringValue != null) s.Append(_stringValue);
// 屬性序列化
if (!String.IsNullOrEmpty(_domain)) s.Append("; domain=").Append(_domain);
if (_expirationSet) s.Append("; expires=").Append(HttpUtility.FormatHttpCookieDateTime(_expires));
if (!String.IsNullOrEmpty(_path)) s.Append("; path=").Append(_path);
if (_secure) s.Append("; secure");
if (_httpOnly && SupportsHttpOnly(context)) s.Append("; HttpOnly");
return new HttpResponseHeader(HttpWorkerRequest.HeaderSetCookie, s.ToString());
}
internal void AddCookie(HttpCookie cookie, bool append) {
// 檢查最大鍵數限制
// append=true:BaseAdd(新增/覆蓋),標記 Added=true
// append=false:BaseSet(強制覆蓋),標記 Changed=true
}
_headersWritten:若已發送響應頭則拋異常「Cannot modify cookies after headers sent」OnCookieAdd 同步至 HttpRequest._cookies 與 _paramsinternal void GenerateResponseHeadersForCookies() {
// 情況一:僅有新增 Cookie → 直接輸出新 Set-Cookie 頭
// 情況二:有修改/刪除 Cookie → 清除所有 Set-Cookie 頭,重寫全部
// IIS 限制:無法刪除特定 Set-Cookie 頭,必須全量重寫
}
| 階段 | 檢查項 | 異常/行為 |
|---|---|---|
| 讀取請求 | 請求驗證 | RequestValidator 驗證 Cookie 值 |
| 寫入響應 | Cookie 數量上限 | 超過 MaxHttpCollectionKeys 拋異常 |
| 寫入響應 | 響應頭是否已發送 | _headersWritten=true 禁止修改 |
| 生成頭 | 是否需全量重寫 | 有修改/刪除時清除重寫所有 |
ASP.NET Cookie 機制本質是:請求端解析 HTTP_COOKIE 頭 → 驗證 → HttpCookieCollection;響應端管理 HttpCookie 狀態 → 生成 Set-Cookie 頭 → 寫入響應頭集合。理解此流程有助於診斷「Cookie 丟失」「headers sent 錯誤」「跨域 Cookie 不生效」等疑難雜症。