http://www.aygfsteel.com/ebecket 返還網(wǎng)
          隨筆-140  評(píng)論-11  文章-131  trackbacks-0

           

          我們先來(lái)看以下幾個(gè)請(qǐng)求,看a.aspx 頁(yè)面用Request.QueryString接受到的是啥信息?

            頁(yè)面URL Request.QueryString["info"]接受到的值
          案例一 a.aspx?info=%25

          %

          案例二 a.aspx?info=%bc%bc%ca%f5

          ????

          情況分析:

          案例一

          a.aspx?info=%25 為何 Request.QueryString["info"]接受到的值是 % ,而不是 %25,是因?yàn)?font style="color: blue; background-color: yellow">Request.QueryString 替我們?cè)诮邮艿街岛螅隽艘淮蜺RL解碼。 HttpUtility.UrlDecode("%25")  的計(jì)算結(jié)果就是 %

          上面的這個(gè)案例一雖然看起來(lái)很簡(jiǎn)單。但是我們?cè)谝恍┨厥鈭?chǎng)景時(shí)候,就會(huì)因?yàn)檫@個(gè)而極度郁悶。

          比如以下幾種情況:

          你有一個(gè)自己的加密算法,而這個(gè)加密算法,某些情況下會(huì)計(jì)算出帶百分號(hào)的結(jié)果,而這個(gè)結(jié)果你是要通過(guò)URL參數(shù)的方式傳遞給其它頁(yè)面的。
          這時(shí)候你就苦惱的發(fā)現(xiàn),某些時(shí)候某個(gè)功能就不能用。

          如果解決案例一碰到的情況呢?

          解決方案一:

          把需要傳遞的參數(shù)傳遞前作一次 HttpUtility.UrlEncode ,
          記得是按照 UTF-8 的編碼的 UrlEncode 。這樣如果我們希望客戶端接受到的是 %25  就應(yīng)該傳遞的是 %2525 。

          切記,不可在接受方每次接受后,自作聰明的都做一次 UrlEncode 。而是在發(fā)送方做 UrlEncode 。
          如果接受方接受后作 UrlEncode 的話,就會(huì)出現(xiàn)下面情況:
          發(fā)送方發(fā)送 a.aspx?info=%25 ,這時(shí)候如果接受方  接受后作 UrlEncode 的話,一切正確
          發(fā)送方發(fā)送 a.aspx?info=% ,這時(shí)候如果接受方  接受后作 UrlEncode 的話,則就亂了。

          另:這套方案中切記, UrlEncode  和 UrlDecode 的次數(shù)應(yīng)該一一對(duì)應(yīng)。不能多一次,也不能少一次。
          有人就會(huì)說(shuō),這還會(huì)出現(xiàn)次數(shù)不對(duì)應(yīng)么? 比如下面情況,一個(gè)不留意就很可能出現(xiàn)次數(shù)不對(duì)應(yīng)。而出現(xiàn)不是你所期望的情況。
          比如我們有這樣類似的功能:

          a.aspx 頁(yè)面中,根據(jù)傳入的 from 參數(shù),自動(dòng)跳轉(zhuǎn)到 from 參數(shù)(用Request.QueryString["from"]來(lái)接受這個(gè)參數(shù))設(shè)置的頁(yè)面。
          b.aspx 頁(yè)面也是同樣的邏輯,根據(jù)傳入的 from 參數(shù)(用Request.QueryString["from"]來(lái)接受這個(gè)參數(shù)),自動(dòng)跳轉(zhuǎn)到指定的頁(yè)面。
          c.aspx 頁(yè)面也是同樣的邏輯,根據(jù)傳入的 from 參數(shù)(用Request.QueryString["from"]來(lái)接受這個(gè)參數(shù)),自動(dòng)跳轉(zhuǎn)到指定的頁(yè)面。


          這樣我們就可能書寫下面的鏈接地址:
          a.aspx?from=b.aspx 
          a.aspx?from=b.aspx?from=c.aspx
          a.aspx?from=b.aspx?from=c.aspx?from=http://blog.joycode.com/ghj/

          下面再?gòu)?fù)雜一點(diǎn),我給下面幾個(gè)鏈接,其中都有 a 這個(gè)參數(shù),請(qǐng)告訴我 a 這個(gè)參數(shù)是被那個(gè)頁(yè)面接受到了?
          說(shuō)明:  HttpUtility.UrlEncode("&")  == "%26"     HttpUtility.UrlEncode("%")  == "%25"

          地址 a 參數(shù)會(huì)被那個(gè)頁(yè)面接受到
          a.aspx?from=b.aspx?from=c.aspx&a=1 a 參數(shù)被 a.aspx 頁(yè)面接受到了
          a.aspx?from=b.aspx?from=c.aspx%26a=1 a 參數(shù)被 b.aspx 頁(yè)面接受到了
          a.aspx?from=b.aspx?from=c.aspx%2526a=1 a 參數(shù)被 c.aspx 頁(yè)面接受到了

          如果想不明白,就想想下面這句話
          每一次用 Request.QueryString 獲取參數(shù)時(shí)候,就作了一次 HttpUtility.UrlDecode。

          解決方案二:

          不用 Request.QueryString ,而是自己實(shí)現(xiàn)一個(gè)獲取查詢參數(shù)的方法。細(xì)節(jié)我在案例二講完后再告訴大家,因?yàn)檫@個(gè)解決方案也處理了案例二的一些情況。

          案例二

          a.aspx?info=%bc%bc%ca%f5 傳給我們的信息其實(shí)是使用 GB2312 編碼后的“技術(shù)” 這兩個(gè)漢字。
          不信,你可以用下面表達(dá)式計(jì)算的結(jié)果就是 %bc%bc%ca%f5
          HttpUtility.UrlEncode("技術(shù)", System.Text.Encoding.GetEncoding("GB2312"))

          ASP.net 系統(tǒng)內(nèi)部,在處理 Request.QueryString 等情況時(shí)候,都是使用的 UTF-8 的編碼,我們?nèi)绻淮嬖诙嘞到y(tǒng)并存的問(wèn)題時(shí)候,這個(gè)問(wèn)題一點(diǎn)都不存在。
          但是,當(dāng)需要跟其它系統(tǒng)交互式后,問(wèn)題就可能會(huì)出現(xiàn)。
          如果你不了解案例二這里情況時(shí),你就會(huì)被這個(gè)問(wèn)題苦惱死。

          比如下面這兩個(gè)地址提到的問(wèn)題:

          ASP.net中的Server.UrlEncode函數(shù)和ASP中的Server.URLEncode函數(shù)返回的值竟然不一樣
          http://blog.joycode.com/ghj/archive/2003/10/20/2992.aspx

          PHP與aspx之間中文通過(guò)URL如何傳遞?
          http://topic.csdn.net/u/20071018/19/8a4066af-a08c-4214-91e9-ed4caf977e07.html

          案例二的解決方案
          使用帶編碼的 HttpUtility.ParseQueryString 函數(shù)

          就是采用類似下面代碼的方式,來(lái)獲得指定格式編碼的查詢文本參數(shù)。

                     System.Collections.Specialized.NameValueCollection nv =
          System.Web.HttpUtility.ParseQueryString(Request.Url.Query, System.Text.Encoding.GetEncoding("GB2312"));
                     Response.Write(nv["Tag"]);

           

          要說(shuō)我為啥知道上面幾種解決方案,是因?yàn)槲矣?Reflector 看了 Request.QueryString 的實(shí)現(xiàn)代碼。在查看代碼時(shí)候,我們會(huì)看到這樣一個(gè) internal 方法:
          System.Web.HttpValueCollection 類的內(nèi)部方法:
          internal void FillFromString(string s, bool urlencoded, Encoding encoding)

          這個(gè)內(nèi)部方法實(shí)現(xiàn)了,按需解密查詢參數(shù)的功能,但是遺憾的是,在QueryString 的處理函數(shù)中,強(qiáng)制指定了解析 QueryString 時(shí),必須作一次 HttpUtility.UrlDecode。參看如下代碼:

          public static NameValueCollection ParseQueryString(string query, Encoding encoding)
          {
              ...
              return new HttpValueCollection(query, false, true, encoding);
          }

          如果我們不想采用案例一的解決方案一,我們就需要自己寫一個(gè)解析查詢信息的代碼。我們完全可以照抄 System.Web.HttpValueCollection 類的 internal void FillFromString(string s, bool urlencoded, Encoding encoding) 方法來(lái)改寫。但郁悶的是:如果你用 Reflector 察看這個(gè)函數(shù)的實(shí)現(xiàn)時(shí)候,Reflector 出來(lái)的代碼是錯(cuò)誤的。正確的方法如下:是在施凡幫助下完成的。

          自己實(shí)現(xiàn)從 URL 查詢文本 Query 中解析出我們自己需要的文本的方法

          /// <summary>
          /// 根據(jù) URL 中的 查詢文本 Query 解析成一個(gè) NameValueCollection
          /// 在裝配腦袋幫助下 郭紅俊 改編自 System.Web.HttpValueCollection 類的內(nèi)部方法:
          /// internal void FillFromString(string s, bool urlencoded, Encoding encoding)
          /// </summary>
          /// <param name="query">需要解析的查詢文本</param>
          /// <param name="urlencoded">解析文本時(shí)候是否需要URL解碼</param>
          /// <param name="encoding">解析文本時(shí)候,按照那種URL編碼進(jìn)行解碼</param>
          /// <returns></returns>
          public static NameValueCollection FillFromString(string query, bool urlencoded, Encoding encoding)
          {
              NameValueCollection queryString = new NameValueCollection();
              if (string.IsNullOrEmpty(query))
              {
                  return queryString;
              }

              // 確保 查詢文本首字符不是 ?
              if (query.StartsWith("?"))
              {
                  query = query.Substring(1, query.Length - 1);
              }

              int num1 = (query != null) ? query.Length : 0;
              // 遍歷每個(gè)字符
              for (int num2 = 0; num2 < num1; num2++)
              {
                  int num3 = num2;
                  int num4 = -1;
                  while (num2 < num1)
                  {
                      switch (query[num2])
                      {
                          case '=':
                              if (num4 < 0)
                              {
                                  num4 = num2;
                              }
                              break;
                          case '&':
                              goto BREAKWHILE;
                      }
                      num2++;
                  }

              BREAKWHILE:

                  string name = null;
                  string val = null;
                  if (num4 >= 0)
                  {
                      name = query.Substring(num3, num4 - num3);
                      val = query.Substring(num4 + 1, (num2 - num4) - 1);
                  }
                  else
                  {
                      val = query.Substring(num3, num2 - num3);
                  }
                  if (urlencoded)
                  {

                      queryString.Add(HttpUtility.UrlDecode(name, encoding), HttpUtility.UrlDecode(val, encoding));
                  }
                  else
                  {
                      queryString.Add(name, val);
                  }
                  if ((num2 == (num1 - 1)) && (query[num2] == '&'))
                  {
                      queryString.Add(null, string.Empty);
                  }
              }

              return queryString;

          }

          用上面的代碼,我們就可以按需解析自己需要的查詢參數(shù),而不是受限的使用Request.QueryString

          小結(jié)

                Request.QueryString 替我們件事情:每次接受到參數(shù)后,都做 UrlEncode ,并且是按照 UTF-8編碼做的 UrlEncode 。 這在大多數(shù)情況下沒(méi)有任何問(wèn)題,但是一些情況下,會(huì)給我們帶來(lái)麻煩,本文就是分析這些可能給我們帶來(lái)麻煩的場(chǎng)景,以及解決方法。

          參考資料:

          使用 Reflector ; 查看代碼時(shí)候,碰到的一個(gè)Reflector 的bug
          http://blog.joycode.com/ghj/archive/2006/12/06/88646.aspx

          解密不同編碼的的參數(shù)。
          http://blog.joycode.com/ghj/archive/2006/04/19/74894.aspx

          posted on 2009-10-16 14:17 becket_zheng 閱讀(287) 評(píng)論(0)  編輯  收藏 所屬分類: web前端開發(fā)
          主站蜘蛛池模板: 延庆县| 兴和县| 微博| 余江县| 化德县| 安阳市| 周宁县| 高州市| 鹿泉市| 阿鲁科尔沁旗| 乌审旗| 云南省| 那曲县| 合江县| 锦屏县| 育儿| 西和县| 礼泉县| 监利县| 鄂伦春自治旗| 弋阳县| 武邑县| 西乡县| 高要市| 延吉市| 湖口县| 巩留县| 盱眙县| 尼勒克县| 莱州市| 南江县| 沁水县| 柳河县| 增城市| 澜沧| 曲阳县| 莆田市| 平潭县| 沾化县| 潮安县| 三门峡市|