
在今天我主要要介紹的有如下知識點: Request Response Server Session Cookie Application <%%>及<%=%>表達式 準(zhǔn)確地說,asp.net并沒有內(nèi)置對象這一說,jsp里確實把request、response這些當(dāng)作jsp的內(nèi)置對象,這里只不過是借用了一下jsp的說法而已。上面提到的很多都是在做asp.net開發(fā)時無需new就能使用的對象(類似的還有很多,在asp.net中所有的網(wǎng)頁都是繼承自System.Web.UI.Page這個類,上面的提到多是Page類的屬性)。 在Web中處于中心的是Web服務(wù)器,用來處理客戶端的HTTP請求。由于HTTP是一種無狀態(tài)的協(xié)議,也就是它并不記得上一次誰請求過它,不會主動去詢問客戶端,只有當(dāng)客戶端主動請求之后,服務(wù)器才會響應(yīng)。 Request
Request封裝了客戶端請求信息。Request的常見屬性如下:
屬性名 | 值類型 | 說明 | ApplicationPath | String | 獲取請求的資源在網(wǎng)站上的根路徑 | ContentEncoding | Encoding | 設(shè)置請求對象的編碼 | Cookies | HttpCookieCollection | 客戶端發(fā)送到服務(wù)器的Cookie集合 | QueryString | NameValueCollection | 當(dāng)前請求的查詢字符串集合 | UrlReferrer | Uri | 獲取用戶由哪個url跳轉(zhuǎn)到當(dāng)前頁面 |
Response Response代表了服務(wù)器響應(yīng)對象。每次客戶端發(fā)出一個請求的時候,服務(wù)器就會用一個響應(yīng)對象來處理這個請求,處理完這個請求之后,服務(wù)器就會銷毀這個相應(yīng)對象,以便繼續(xù)接受其它客服端請求。 Response常用屬性如下:
屬性名 | 值類型 | 說明 | Charset | string | 表示輸出流的所使用的字符集 | ContentEncoding | Encoding | 設(shè)置輸出流的編碼 | ContentLength | Int | 輸出流的字節(jié)大小 | ContentType | string | 輸出流的HTTP MIME類型 | Cookies | HttpCookieCollection | 服務(wù)器發(fā)送到客戶端的Cookie集合 | Output | TextWriter | 服務(wù)器響應(yīng)對象的字符輸出流 | RedirectLocation | string | 將當(dāng)前請求重定向 |
Response常用方法 屬性名 | 返回值類型 | 說明 | AppendCookie | void | 向響應(yīng)對象的Cookie集合中增加一個Cookie | Clear | void | 清空緩沖區(qū)中的所有內(nèi)容輸出 | Close | void | 關(guān)閉當(dāng)前服務(wù)器到客戶端的連接 | End | void | 終止響應(yīng),并且將緩沖區(qū)中的輸出發(fā)送到客戶端 | Redirect | void | 重定向當(dāng)前請求 |
下面距離說明,用Dreamweaver8創(chuàng)建一個aspx頁面,代碼如下: <%@ Page Language='C#' ContentType='text/html' ResponseEncoding='gb2312' %> <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www./1999/xhtml'> <head> <meta http-equiv='Content-Type' content='text/html; charset=gb2312' /> <title>Request例子</title> </head> <body> <table border='1' width='600px' bordercolordark='#2B72A2' bordercolorlight='#993333'> <tr><td colspan='2' bgcolor='#80ffff'>Request</td></tr> <tr><td>ApplicationPath(網(wǎng)站路徑)</td><td><%=Request.ApplicationPath%></td></tr> <tr><td>ContentEncoding(網(wǎng)頁編碼)</td><td><%=Request.ContentEncoding%></td></tr> <tr><td>Cookies個數(shù)</td><td><%=Request.Cookies.Count%></td></tr> <tr><td>QueryString個數(shù)</td><td><%=Request.QueryString.Count%></td></tr> <tr><td>UrlReferrer(上一請求頁面)</td><td> <%=Request.UrlReferrer%></td></tr> <tr><td colspan='2' bgcolor='#80ffff'>Response</td></tr> <tr><td>Charset</td><td><%=Response.Charset%></td></tr> <tr><td>ContentEncoding(網(wǎng)頁編碼)</td><td><%=Response.ContentEncoding%></td></tr> <tr><td>Cookies個數(shù)</td><td><%=Response.Cookies.Count%></td></tr> <tr><td>ContentType</td><td><%=Response.ContentType%></td></tr> </table> </body> </html>
將新建的頁面保存為RequestAndResponse.aspx并保存到C:/Inetpub/wwwroot下,然后打開瀏覽器在地址欄中輸入:http://localhost/RequestAndResponse.aspx,實際上url地址不區(qū)分大小寫,以上地址全部小寫也沒有關(guān)系,運行結(jié)果如下:  從上面的結(jié)果我們可以看出利用Dreamweaver創(chuàng)建的網(wǎng)頁,如果采用默認編碼,請求對象的字符編碼是UTF-8,而響應(yīng)對象的編碼為gb2312。這樣極有可能可能產(chǎn)生亂碼問題。所謂亂碼,就是用一種編碼的字符串卻用了另一種編碼來顯示,造成不能正常顯示的現(xiàn)象。就像我用普通話說“請給我來一杯茶“,結(jié)果是一個只懂德育的人聽了,他自然聽不懂我說什么,不能正常交流。另外,需要說明的是常見的服務(wù)器響應(yīng)的ContentType是“text/html”,代表響應(yīng)是以HTML文件形式傳輸?shù)?。還有一些其它形式的ContentType,如下: image/jpeg:響應(yīng)對象是jpeg圖片 text/xml:響應(yīng)對象是xml文件 text/javascript:響應(yīng)對象是javascript腳本文件 Response的ContentType屬性默認是“text/html”,表示服務(wù)器以HTML文件響應(yīng)客戶端請求,如果需要用其它方式響應(yīng)客戶端請求,則需要設(shè)置ContentType屬性。假如我們需要用jpeg圖片的格式響應(yīng)客戶端請求,則需要設(shè)置ContentType屬性為“image/jpeg”,然后將圖片內(nèi)容輸出到客戶端,這樣客戶端就會看到j(luò)peg格式的圖片而不是HTML文件。 Server Server對象是用于獲取服務(wù)器的相關(guān)信息的對象。它常用方法如下:
屬性名 | 返回值類型 | 說明 | Execute | void | 執(zhí)行指定的資源,并且在執(zhí)行完之后再執(zhí)行本頁的代碼 | HtmlDecode | string | 消除對特殊字符串編碼的影響 | HtmlEncode | string | 對特殊字符串進行編碼 | MapPath | string | 獲取指定相對路徑在服務(wù)器上的無力路徑 | Transfer | void | 停止執(zhí)行當(dāng)前程序,執(zhí)行指定的資源 | UrlDecode | string | 對路徑字符串進行解碼 | UrlEncode | string | 對路徑字符串進行編碼 |
上面的方法光從概念上來說,似乎還是讓人不能分清他們到底有什么作用,特別Excure/ Transfer、HtmlEncode(HtmlDecode)/ UrlEncode(UrlDecode)這兩組。在講述他們分別之前先講述MapPath這個方法的作用,在我們上傳文件的時候要以物理路徑保存上傳文件到服務(wù)器,而我們使用得最多的是相對URL地址,這個方法就起到了將相對URL地址轉(zhuǎn)換成服務(wù)器物理路徑的作用。 為了說明Excure/ Transfer及HtmlEncode(HtmlDecode)/ UrlEncode(UrlDecode)的區(qū)別,我們還是用實例代碼來展示,用Dreamweaver8創(chuàng)建一個aspx頁面,代碼如下: <%@ Page Language='C#' ContentType='text/html' ResponseEncoding='gb2312' %> <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www./1999/xhtml'> <head> <meta http-equiv='Content-Type' content='text/html; charset=gb2312' /> <title>Server對象的常見方法實例</title> </head> <body> <ul> <li>Server.MapPath('.')=<%=Server.MapPath('.')%></li> <li><%=Server.HtmlEncode('<h1>Asp.net夜話之二:asp.net內(nèi)置對象</h1>')%></li> <li><h1>Asp.net夜話之二:asp.net內(nèi)置對象</h1></li> <li><%=Server.UrlEncode('<a href=/'http://blog.csdn.net/zhoufoxcn/'>周公的專欄</a>')%></li> <li><a href='http://blog.csdn.net/zhoufoxcn'>周公的專欄</a></li> </ul> </body> </html>
將新建的頁面保存為ServerDemo.aspx并保存到C:/Inetpub/wwwroot下,然后打開瀏覽器在地址欄中輸入:http://localhost/Request/serverdemo.aspx,運行結(jié)果如下:
從Server.MathPath(“.”)輸出“C:/Inetpub/wwwroot”,證明確實能獲取到相對路徑的在服務(wù)器上的實際物理地址。 在上面的例子中我們想在網(wǎng)頁中輸出HTML代碼,如果直接輸出往往得不到想要的效果,這時可以借助HtmlEncode方法對要輸出的HTML代碼進行編碼,這樣輸出到瀏覽器上的時候就能看到HTML代碼,而不是HTML形式的效果。HtmlDecode方法則是用來消除這種影響。 如果我們直接輸出“<a href='http://blog.csdn.net/zhoufoxcn'>周公的專欄</a>”這個字符串的話,在網(wǎng)頁上會顯示一個超級鏈接,但是有時候我們希望把這個超級鏈接作為QueryString的一個參數(shù),由于url地址的特殊性,比如“:”、“/”等字符串在URL地址中有特殊的含義,要想輸出這些字符,直接輸出是不行的,需要進行某種轉(zhuǎn)換,并且將來還能轉(zhuǎn)換回來。經(jīng)過UrlEncode方法轉(zhuǎn)換之后,“:”、“/”分別轉(zhuǎn)換成了“%3a”和“%2f”這樣的字符,并且漢字也進行了轉(zhuǎn)換。UrlDecode方法則是將“%3a”和“%2f”等這樣的字符轉(zhuǎn)換成我們原本要表示的字符。 前面我們提到,在HTTP中,服務(wù)器與客戶端并不是時時保持連接狀態(tài),而是服務(wù)器被動地等待客戶發(fā)送請求,服務(wù)器才進行響應(yīng)。因此,在大部分情況下,服務(wù)器并不會管客戶端是否還依然存在。 在這種情況下,假如用戶通過訪問一些需要權(quán)限的頁面,在他輸入正確的用戶名和密碼之后第一次他訪問a頁面,隔幾分鐘之后再訪問同樣需要權(quán)限才能訪問的b頁面,這是他還需要輸入用戶名和密碼嗎?按照清理來說如果這個時間間隔比較短,我們不應(yīng)該要求頻繁用戶輸入這些信息,可是服務(wù)器又不記錄這些信息,我們有沒有辦法解決這個問題呢? 答案是有的,就是利用Session或者Cookie。 Session Session對象用來保存與特定用戶相關(guān)的信息,Session中的數(shù)據(jù)保存在服務(wù)器端,在客戶端需要的時候創(chuàng)建Session,在客戶端不需要的時候銷毀Session,使它不再占用服務(wù)器內(nèi)存。前面說了服務(wù)器并不管客戶端是否依然存在,因而它也無法確定客戶端什么時間不再使用它,但是如果在客戶端不再用的時候不及時銷毀Session的話,服務(wù)器很快就會內(nèi)存不足。為了解決這個問題,給Session加了一個生命周期,當(dāng)服務(wù)器發(fā)現(xiàn)Session超過了它的生命周期,就會釋放該Session所占用的內(nèi)存空間。在asp.net中Session的默認生命周期是20分鐘,也就是當(dāng)我們在9:00的時候設(shè)置了一個Session,如果在9:20之前客戶端沒有任何請求,那么它的生命周期就到9:20分鐘結(jié)束。但是一旦用戶在9:19又向服務(wù)器發(fā)送了一個請求,那么這個Session現(xiàn)在的生命周期就是在當(dāng)前時間的基礎(chǔ)上再加上20分鐘,也就是此時這個Session的生命周期是到9:39結(jié)束。 Session具有以下特點: Session中的數(shù)據(jù)保存在服務(wù)器端; Session中可以保存任意類型的數(shù)據(jù); Session默認的生命周期是20分鐘,可以手動設(shè)置更長或更短的時間。 假設(shè)我們要設(shè)置一個Session用來保存用戶名,這個Session的名字是“UserName”,值是“zhoufoxcn”,代碼如下:
Session[“UserName”]=”zhoufoxcn”;
一個網(wǎng)站里用到Session的地方肯定不止一個,所以在設(shè)置和獲取Session的時候通過Session的名在來操作,并且Session被設(shè)置成能存儲任意類型的對象(即Object類型),所以獲取Session的時候要根據(jù)設(shè)置的時候的實際類型進行響應(yīng)的強制類型轉(zhuǎn)換(當(dāng)然如果在Session中存放像int/byte/short這樣的數(shù)據(jù)類型,獲取Session的值算是一種拆箱操作而不是強制類型轉(zhuǎn)換),對于上面的Session,獲取Session的值的代碼如下: string username=(string)Session[“UserName”];
對于上面的代碼,有個問題需要注意:當(dāng)沒有設(shè)置相應(yīng)的Session或者Session因為超過生命周期而被銷毀時,上面的代碼有可能拋出異常。我們可以先判斷是否存在指定名稱的Session,如果不存在就不用獲取了,僅當(dāng)存在的情況下才獲取Session的值,上面的代碼可以改進如下:
string userName; if(Session['UserName']!=null) { //當(dāng)指定名稱的Session存在時,獲取指定Session的值 userName=(string)Session['UserName']; }
Cookie Cookie對象和Session對象一樣也是用來保存特定的用戶相關(guān)的數(shù)據(jù),不過Session不同的是Cookie保存在客戶端而不是服務(wù)器上,每次客戶端發(fā)出請求的時候都會把Cookie一起發(fā)送到服務(wù)器,服務(wù)器每次響應(yīng)客戶端請求的時候會重新把Cookie發(fā)送到客戶端保存。 Cookie保存數(shù)據(jù)有以下特點: Cookie中的數(shù)據(jù)保存在客戶端; Cookie中只能保存字符串類型的數(shù)據(jù),如果需要在Cookie中保存其它類型數(shù)據(jù),需要將其轉(zhuǎn)換成字符串類型后保存; Cookie也有其默認生命周期,也可以手動設(shè)置,最大可設(shè)置成50年之后過期。 同Session的情況一樣,有可能在一個網(wǎng)站中使用到的Cookie不止一個,我們?nèi)酝ㄟ^Cookie的名稱來區(qū)分不同的Cookie。 設(shè)置Cookie的過程就是在服務(wù)器的響應(yīng)對象Response的Cookie集合中增加一個Cookie的實際,Response對象會把這個Cookie集合中的所有Cookie都發(fā)送客戶端。代碼如下(仍以保存用戶名為例):
HttpCookie cookie = new HttpCookie('UserName', 'zhoufoxcn'); Response.Cookies.Add(cookie);
獲取Cookie就是從客戶端的請求對象中找到對應(yīng)名稱的Cookie,當(dāng)然也有可能出現(xiàn)Cookie不存在的情況,所以在獲取之前也需要檢查指定名稱的Cookie是否存在,大媽如下:
string userName; if (Request.Cookies['UserName'] != null) { userName = Request.Cookies['UserName'].Value; }
細心的朋友可能會留意到前面講到Session和Cookie的時候,我都說他們是針對特定用戶保存的數(shù)據(jù),也就是那些數(shù)據(jù)并不是每個人都能用到。Session和Cookie一般用來一些針對特定用戶的信息,比如用于保存用戶名等,因為是針對特定用戶的,所以不會針對張三設(shè)置用戶名保存在Session或者Cookie中之后再去或者這個值的時候得到的是李四的用戶名。但是在某些情況下,我們又希望保存一些共有信息,這樣大家都能設(shè)置或者獲取,比如自從服務(wù)器啟動以來某個頁面被打開的次數(shù),這時用Session或者Cookie就不合適了。這就需要用Application了。
Application Application和Session存儲的數(shù)據(jù)類型和存儲位置一樣,都是存放Object類型的數(shù)據(jù)(也就是任意類型),并且存放在服務(wù)器上,不同的Application中的數(shù)據(jù)可以由網(wǎng)站中所有的用戶來設(shè)置或者獲取。并且Application中存放的數(shù)據(jù)沒有時間限制,除非我們手動刪除或者服務(wù)器重新啟動,否則存放的數(shù)據(jù)都會丟失。 下面是Session、Cookie和Application的區(qū)別:名稱 | 使用范圍 | 存儲位置 | 存放數(shù)據(jù)類型 | 生命周期 | Session | 特定用戶 | 服務(wù)器 | Object,也就是任意類型 | 有,可以自行設(shè)置 | Cookie | 特定用戶 | 客戶端 | String,也就值字符串 | 可以自行設(shè)置 | Application | 所有用戶 | 服務(wù)器 | Object,也就是任意類型 | 無 |
下面我們以一個小例子來說明Session和Application的區(qū)別。 我們用Dreamweaver8創(chuàng)建兩個頁面,分別為SessionTest.aspx和ApplicationTest.aspx,保存到C:/Inetpub/wwwroot目錄下,它們的代碼都是一樣的,如下:
<%@ Page Language='C#' ContentType='text/html' ResponseEncoding='gb2312' %> <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www./1999/xhtml'> <head> <meta http-equiv='Content-Type' content='text/html; charset=gb2312' /> <title>Application和Session的例子</title> </head> <body> <% //如果沒有設(shè)置名為'ApplicationCount'的Application int applicationCount=1; int sessionCount=1; if(Application['ApplicationCount']==null) { Application['ApplicationCount']=1; } else//否則取出該Session,并且在當(dāng)前值上加1 { applicationCount=(int)Application['ApplicationCount']+1; Application['ApplicationCount']=applicationCount; } //如果Session['SessionCount']為空,即沒有設(shè)置該名字的Session if(Session['SessionCount']==null) { Session['SessionCount']=1; } else { sessionCount=(int)Session['SessionCount']+1; Session['SessionCount']=sessionCount; } Response.Write('當(dāng)前頁面由Application記錄到的被訪問了'+applicationCount+'次<br/>'); Response.Write('當(dāng)前頁面由Session記錄到的被訪問了'+sessionCount+'次<br/>'); %> </body> </html>
這時我們在瀏覽器地址欄里輸入:http://localhost/sessiontest.aspx,會看如下結(jié)果Session和Application中的值是一樣的,即使我們按F5刷新頁面,結(jié)果也是一樣,如下圖:  然后我們重新打開一個瀏覽器應(yīng)用程序(注意不要在當(dāng)前窗口中輸入),會看到如下情況: 為什么特地強調(diào)要在新瀏覽器窗口中打開另一個頁面呢?因為有些瀏覽器會視同為同一個Session,導(dǎo)致出現(xiàn)不了預(yù)期的效果。通過上面的例子證明了Application確實是屬于所有網(wǎng)站用戶的,它適合保存全局的數(shù)據(jù)信息,如網(wǎng)站從Web服務(wù)器啟動以來接受的請求個數(shù)或者當(dāng)前在線總?cè)藬?shù);而Session只與特定用戶有關(guān),只適合保存特定用戶的信息,比如用戶的用戶名。
<%%>表達式 <%%>用來編寫程序的代碼部分。在其中可以聲明變量和方法。如下:
<% string name = Request.Form['userName'].Trim(); string userName; if (Request.Cookies['UserName'] != null) { userName = Request.Cookies['UserName'].Value; } %>
在<%%>就是符合C#要求的代碼。 <%=%>表達式 <%=%>是用來向輸出流中輸出變量的值。其用法如下: <% int i = 6; %> <%=i %> 九九乘法表是大家相當(dāng)熟悉的了,下面我們分別用Response對象的Write方法和上面的<%%>及<%=%>來輸出九九乘法表。如下圖
用Response對象輸出九九乘法表的代碼如下: <%@ Page Language='C#' ContentType='text/html' ResponseEncoding='gb2312' %> <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www./1999/xhtml'> <head> <meta http-equiv='Content-Type' content='text/html; charset=gb2312' /> <title>Server對象的常見方法實例</title> </head> <body> <table border='1' width='600px'> <tr><th colspan='9'>九九乘法表</th></tr> <% for(int i=1;i<10;i++) { Response.Write('<tr>'); for(int j=1;j<10;j++)//輸出一行中的每列 { if(j<=i){//如果有內(nèi)容 Response.Write(String.Format('<td>{0}×{1}={2}</td>',j,i,j*i)); } else{//否則輸出空單元格 Response.Write('<td> </td>'); } } Response.Write('</tr>'); } %> </body> </html>
用<%%>及<%=%>輸出九九乘法表的代碼如下: <%@ Page Language='C#' ContentType='text/html' ResponseEncoding='gb2312' %> <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www./1999/xhtml'> <head> <meta http-equiv='Content-Type' content='text/html; charset=gb2312' /> <title>九九乘法表</title> </head> <body> <table border='1' width='600px'> <tr><th colspan='9'>九九乘法表</th></tr> <% for(int i=1;i<10;i++) { %> <tr> <% for(int j=1;j<10;j++)//輸出一行中的每列 { if(j<=i){//如果有內(nèi)容 %> <td><%=j%>×<%=i%>=<%=i*j%></td> <% } else{//否則輸出空單元格 %> <td> </td> <%} } %> </tr> <%} %> </body> </html>
可以看出用Response.Write()輸出和<%=%>輸出最后的效果是一樣的。
|