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