5.5 HTTP Cookies in ASP.NET Web API
5.5 ASP.NET Web API中的HTTP Cookie
本文引自:http://www.asp.net/web-api/overview/working-with-http/http-cookies
By Mike Wasson|September 17, 2012
作者:Mike Wasson | 日期:2012-9-17
This topic describes how to send and receive HTTP cookies in Web API.
本主題描述如何在Web API中發送和接收HTTP Cookie。
Background on HTTP Cookies
HTTP Cookie的背景知識
This section gives a brief overview of how cookies are implemented at the HTTP level. For details, consult RFC 6265.
本小節給出在HTTP層面上如何?Cookies,詳細參考RFC 6265。
A cookie is a piece of data that a server sends in the HTTP response. The client (optionally) stores the cookie and returns it on subsequet requests. This allows the client and server to share state. To set a cookie, the server includes a Set-Cookie header in the response. The format of a cookie is a name-value pair, with optional attributes. For example:
Cookie是伺服器在HTTP響應中發送的一個資料片段。用戶端儲存此Cookie(可選),並在後繼的請求中返回它。這讓用戶端和伺服器端可以共用狀態。為了設定一個Cookie,伺服器需要在響應中包含一個Set-Cookie前序。Cookie的格式是一個“名字-值”對,並帶有一些可選屬性。例如:
Set-Cookie: session-id=1234567
Here is an example with attributes:
以下是一個帶有屬性的樣本:
Set-Cookie: session-id=1234567; max-age=86400; domain=example.com; path=/;
To return a cookie to the server, the client includes a Cookie header in later requests.
為了將一個Cookie返回給伺服器,用戶端在後繼的請求中要包含一個Cookie前序。
Cookie: session-id=1234567
An HTTP response can include multiple Set-Cookie headers.
一個HTTP響應可以包含多個Set-Cookie前序。
Set-Cookie: session-token=abcdef;Set-Cookie: session-id=1234567;
The client returns multiple cookies using a single Cookie header.
用戶端用一個單一的Cookie前序返回多個Cookie。
Cookie: session-id=1234567; session-token=abcdef;
The scope and duration of a cookie are controlled by following attributes in the Set-Cookie header:
Cookie的範圍和期限是受Set-Cookie前序的以下屬性控制的:
- Domain: Tells the client which domain should receive the cookie. For example, if the domain is “example.com”, the client returns the cookie to every subdomain of example.com. If not specified, the domain is the origin server.
Domain(主域,或簡稱為域):告訴用戶端哪一個域應當接收此Cookie。例如,如果Domain是“example.com”,那麼用戶端要把Cookie返回給example.com的每個子域。如果未指定,這個域便是原伺服器。
- Path: Restricts the cookie to the specified path within the domain. If not specified, the path of the request URI is used.
Path(路徑):將Cookie限制到主域的特定路徑。如果未指定,則使用請求URI的路徑。
- Expires: Sets an expiration date for the cookie. The client deletes the cookie when it expires.
Expires(到期):設定Cookie的到期日期。當Cookie到期時,用戶端刪除此Cookie。
- Max-Age: Sets the maximum age for the cookie. The client deletes the cookie when it reaches the maximum age.
Max-Age(最大年齡):設定Cookie的最大年齡。當Cookie達到最大年齡時,用戶端刪除此Cookie。
If both Expires and Max-Age are set, Max-Age takes precedence. If neither is set, the client deletes the cookie when the current session ends. (The exact meaning of “session” is determined by the user-agent.)
如果Expires和Max-Age都設定,則Max-Age優先。如果都未設定,在當前會話結束時,用戶端刪除Cookie。(“會話”的確切含意是由使用者代理程式確定的。)
However, be aware that clients may ignore cookies. For example, a user might disable cookies for privacy reasons. Clients may delete cookies before they expire, or limit the number of cookies stored. For privacy reasons, clients often reject “third party” cookies, where the domain does not match the origin server. In short, the server should not rely on getting back the cookies that it sets.
然而,要意識到用戶端可能會忽略Cookie。例如,一個使用者可能由於私人原因禁用了Cookies。用戶端可能會在到期之前刪除Cookies,或限制儲存Cookies的數目。出於私人原因,用戶端通常會拒絕與原始伺服器域不匹配的“第三方”Cookie。簡言之,伺服器不應該對取回它所設定的Cookie有依賴性。
Cookies in Web API
Web API中的Cookies
To add a cookie to an HTTP response, create a CookieHeaderValue instance that represents the cookie. Then call the AddCookies extension method, which is defined in the System.Net.Http. HttpResponseHeadersExtensions class, to add the cookie.
為了對一個HTTP響應添加Cookie,需要建立一個表示Cookie的CookieHeaderValue執行個體。然後調用AddCookies擴充方法(這是在System.Net.Http.HttpResponseHeadersExtensions類中定義的),以添加一個Cookie。
For example, the following code adds a cookie within a controller action:
例如,以下代碼在一個控制器動作中添加了一個Cookie:
public HttpResponseMessage Get() { var resp = new HttpResponseMessage();
var cookie = new CookieHeaderValue("session-id", "12345"); cookie.Expires = DateTimeOffset.Now.AddDays(1); cookie.Domain = Request.RequestUri.Host; cookie.Path = "/";
resp.Headers.AddCookies(new CookieHeaderValue[] { cookie }); return resp; }
Notice that AddCookies takes an array of CookieHeaderValue instances.
注意,AddCookies採用的是一個CookieHeaderValue執行個體數組。
To extract the cookies from a client request, call the GetCookies method:
為了提取用戶端請求的Cookie,需要調用GetCookies方法:
string sessionId = "";
CookieHeaderValue cookie = Request.Headers.GetCookies("session-id").FirstOrDefault(); if (cookie != null) { sessionId = cookie["session-id"].Value; }
A CookieHeaderValue contains a collection of CookieState instances. Each CookieState represents one cookie. Use the indexer method to get a CookieState by name, as shown.
CookieHeaderValue含有CookieState執行個體的集合。每個CookieState表示一個Cookie。使用索引器方法(指上述代碼最後一行的cookie["session-id"] — 譯者注)可以得到由名稱表示的CookieState,如上所示。
Structured Cookie Data
結構化的Cookie資料
Many browsers limit how many cookies they will store—both the total number, and the number per domain. Therefore, it can be useful to put structured data into a single cookie, instead of setting multiple cookies.
許多瀏覽器會限制其儲存的Cookie數 — Cookie總數和每個域的Cookie數。因此,把結構化的資料放入一個Cookie而不是設定多個Cookie可能是有用的。
RFC 6265 does not define the structure of cookie data.
RFC 6265並未定義Cookie資料的結構。
Using the CookieHeaderValue class, you can pass a list of name-value pairs for the cookie data. These name-value pairs are encoded as URL-encoded form data in the Set-Cookie header:
使用CookieHeaderValue類,你可以為Cookie資料傳遞一組“名字-值”對。這些“名字-值”對是在Set-Cookie前序中作為URL編碼的表單資料進行編碼的:
var resp = new HttpResponseMessage();
var nv = new NameValueCollection(); nv["sid"] = "12345"; nv["token"] = "abcdef"; nv["theme"] = "dark blue"; var cookie = new CookieHeaderValue("session", nv);
resp.Headers.AddCookies(new CookieHeaderValue[] { cookie });
The previous code produces the following Set-Cookie header:
上述代碼產生以下Set-Cookie前序:
Set-Cookie: session=sid=12345&token=abcdef&theme=dark+blue;
The CookieState class provides an indexer method to read the sub-values from a cookie in the request message:
CookieState類提供了一個索引器方法,以讀取請求訊息中Cookie的子值(Sub-values):
string sessionId = ""; string sessionToken = ""; string theme = "";
CookieHeaderValue cookie = Request.Headers.GetCookies("session").FirstOrDefault(); if (cookie != null) { CookieState cookieState = cookie["session"];
sessionId = cookieState["sid"]; sessionToken = cookieState["token"]; theme = cookieState["theme"]; }
Example: Set and Retrieve Cookies in a Message Handler
樣本:在訊息處理器中設定和接收Cookie
The previous examples showed how to use cookies from within a Web API controller. Another option is to use message handlers. Message handlers are invoked earlier in the pipeline than controllers. A message handler can read cookies from the request before the request reaches the controller, or add cookies to the response after the controller generates the response.
前述樣本示範了如何使用來自Web API控制器的Cookie。另一種選擇是使用“訊息處理器(Message Handler,也可以稱為訊息處理常式 — 譯者注)”。訊息處理器的調用在請求管線中要早於控制器。訊息處理器可以在請求到達控制器之前讀取請求的Cookie,或者,在控制器產生響應之後將Cookie添加到響應(如所示)。
The following code shows a message handler for creating session IDs. The session ID is stored in a cookie. The handler checks the request for the session cookie. If the request does not include the cookie, the handler generates a new session ID. In either case, the handler stores the session ID in the HttpRequestMessage.Properties property bag. It also adds the session cookie to the HTTP response.
以下代碼示範了一個建立會話ID的訊息處理器。會話ID是儲存在一個Cookie中的。該處理器檢查請求的會話Cookie。如果請求不包含Cookie,處理器便產生一個新會話的ID。在任一情況下,處理器都會將這個會話ID儲存在HttpRequestMessage.Properties屬性包中。它也將這個會話Cookie添加到HTTP響應。
This implementation does not validate that the session ID from the client was actually issued by the server. Don't use it as a form of authentication! The point of the example is to show HTTP cookie management.
如果用戶端的會話ID實際是由伺服器發布的,該實現不會驗證它。不要把它用於認證場合!本例的關鍵是示範HTTP Cookie的管理。
using System; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using System.Web.Http;
public class SessionIdHandler : DelegatingHandler { static public string SessionIdToken = "session-id";
async protected override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { string sessionId;
// Try to get the session ID from the request; otherwise create a new ID. // 嘗試擷取請求的會話ID,否則建立一個新的ID var cookie = request.Headers.GetCookies(SessionIdToken).FirstOrDefault(); if (cookie == null) { sessionId = Guid.NewGuid().ToString(); } else { sessionId = cookie[SessionIdToken].Value; try { Guid guid = Guid.Parse(sessionId); } catch (FormatException) { // Bad session ID. Create a new one. // 劣質會話ID,建立一個新的 sessionId = Guid.NewGuid().ToString(); } }
// Store the session ID in the request property bag. // 在請求的屬性包中儲存會話ID request.Properties[SessionIdToken] = sessionId;
// Continue processing the HTTP request. // 繼續處理HTTP請求 HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
// Set the session ID as a cookie in the response message. // 將會話ID設定為響應訊息中的一個Cookie response.Headers.AddCookies(new CookieHeaderValue[] { new CookieHeaderValue(SessionIdToken, sessionId) });
return response; } }
A controller can get the session ID from the HttpRequestMessage.Properties property bag.
控制器可以通過HttpRequestMessage.Properties屬性包來擷取會話ID。
public HttpResponseMessage Get() { string sessionId = Request.Properties[SessionIdHandler.SessionIdToken] as string;
return new HttpResponseMessage() { Content = new StringContent("Your session ID = " + sessionId) }; }
看完此文如果覺得有所收穫,請給個推薦