錯誤描述:
反序列化時出現“base-64 字符數組的無效長度”錯誤提示的解決程序中實現了這樣一個功能,將一個對象序列化后,作為參數傳遞給另一個頁面,這個頁面得到參數並反序列化后還原此對象,但是在運行時有時正常,有時出現“base-64 字符數組的無效長度”的錯誤提示。
解決方案:
1、根據現象的解決方案
在網上查找資料,都是說在使用Convert.ToBase64String()方法對字符串進行Base64編碼時,需要使參數的長度等於4或4的偶數倍數,否則將拋出“FormatException”異常(這個觀點並不是正確的)。但是我這里使用的參數是使用Convert.ToBase64String()方法生成的,理論上是沒有問題的。於是對比用Convert.ToBase64String()生成的字符串A與反序列化前Convert.ToBase64String()所使用的參數字符串B,發現A與B之間有差異,A中的加號變成了空格(base64編碼后是允許存在’’)。這是由於網頁傳遞參數時,會將加號編碼成空格,但是在解碼時卻不會解碼空格,結果就造成了字符串B不正確,無法背編碼。確認了問題就好辦了,在得到序列化字符串后,使用String.Replace("", "")先將空格編碼,然后再作為參數傳給另一頁面傳遞,這樣頁面在提取參數時才會將“”解碼為加號,參數沒有差別,在執行反序列化成功就通過了。
http://localhost:3204/return_url.aspx?toBase64=0KG+9dK5
不過通過Request.QueryString["toBase64"]獲得到的值是:
2、根據本質的解決方案:
后面再去網上搜索了資料,我們對對象Base64編碼后的字符串應先行url編碼再傳遞,這樣在url傳遞的參數就不存在’+’了。而在獲取參數端是不需要再解碼,
因為使用默認的Request.QueryString和Request.Form時已經自動執行了一次解碼,使用的解碼格式是服務器端設置的默認編碼格式。
而如果對Request.QueryString得到的值進行UrlDecode解碼再進行ToBase64就會出錯,因為就相當於2次解碼。
分享資料
參數編碼規范
一.摘要
我們經常要在頁面傳遞中文數據,但是往往被文字編碼所困惑.有時不了解到底是瀏覽器編碼問題還是服務器編碼問題.本文分析了互聯網傳遞數據的編碼原理, 並且提出了完善易用的解決方案.
二.原則
避免在get或者post參數時直接傳遞中文字符.中文參數需要經過編碼后再傳遞.服務器端要使用相同的編碼格式進行解碼
三.錯誤觀點
1.很多程序員認為url中可以傳遞中文. url中並不能攜帶中文參數.如果我們在瀏覽器中輸入"http://localhost/?a=中文",感覺上我們在url中帶了中文,實際上當按下回車鍵后,瀏覽器自動將其中的"中文"漢字進行編碼后傳遞給服務器.
2.當獲取中文參數產生了亂碼時, 往往首先檢查服務器端程序的編碼格式. 很多人認為url可以傳遞中文,不知道瀏覽器有自動編碼的行為, 所以單純的認為問題出在服務器端.其實即使在服務器端找到了正確的編碼格式,我們也不應該輕易地改變服務器的默認編碼格式.
3.傳遞參數前編碼,使用Request對象獲取參數時解碼 很多的程序員認為認為,傳遞參數時我們使用UrlEncode等方式編碼, 在接收時應該使用UrlDecode解碼.這是常見的錯誤請大家一定要注意,使用默認的Request.QueryString和Request.Form時已經自動執行了一次解碼,使用的解碼格式是服務器端設置的默認編碼格式.
四.原因
傳遞中文字符時,自動的編碼解碼格式和瀏覽器與服務器的設置有關. 測試Firefox3和IE6的Get方式發送中文參數, Firefox默認使用UTF-8格式編碼中文參數, 而IE6即使在高級設置中設置了"總是以 UTF-8 發送URL", 仍然自動使用GB2312編碼中文參數. 對於服務器端我們可以自由的控制解碼的格式.但是往往是通過更改服務器配置進行全局的統一設置.比如對於ASP.NET程序.可以在Web.Config中設置服務器段的編碼和解碼格式: <globalization culture="zh-CN" uiCulture="zh-CN" requestEncoding="UTF-8" responseEncoding="gb2312" /> 但是我們沒法控制瀏覽器端行為.用戶可能使用不同的瀏覽器.
五.解決方案
1.統一默認的編碼格式 (1)設置服務器端的編碼格式為UTF-8 (2)傳遞參數全部進行編碼,.服務器端(C#)使用Server.UrlEncode方法,客戶端(javascript)使用encodeURIComponent方法. 說明: 客戶端的javascript函數encodeURIComponent只能使用UTF-8編碼格式. 所以需要設置服務器端request和response都為UTF-8. 缺陷是如果某些合作伙伴必須傳遞其他的編碼格式的參數, 則服務器端或獲取到亂碼.此方案實現簡單,適合大部分場景. 2.通過編碼參數指定編碼格式 為了解決可能存在的無法統一編碼格式的問題, 我們使用一個參數"encoding"來顯示的指定編碼格式.encoding參數需要在所有的請求中傳遞,無論是get還是post. (1)對於javascript客戶端編碼而言, 仍然使用encodeURIComponent方法編碼, 此時指定encoding參數的值為"UTF-8". (2) 對於傳入給服務器端的其他編碼格式, 比如GB2312, 我們不能使用默認的Request.Form或者QueryString方法進行編碼.因為服務器端的編碼格式可能設置為了UTF-8.此時使用 Request.Form或者QueryString會自動使用服務器端指定的編碼格式進行解碼. 所以需要使用下面的方法自己處理請求,獲取參數:
1 /// <summary> 2 /// 根據指定的編碼格式返回請求的參數集合 3 /// </summary> 4 /// <param name="request">當前請求的request對</param> 5 /// <param name="encode">編碼格式字符串</param> 6 /// <returns>鍵為參數名,值為參數值的NameValue集合</returns> 7 public static NameValueCollection GetRequestParameters(HttpRequest request, string encode) 8 { 9 NameValueCollection result = null; 10 Encoding destEncode = null;//獲取指定編碼格式的Encoding對象 11 if (!String.IsNullOrEmpty(encode)) 12 { 13 try 14 { 15 //獲取指定的編碼格式 16 destEncode = Encoding.GetEncoding(encode); } 17 catch 18 { 19 //如果獲取指定編碼格式失敗,則設置為null 20 destEncode = null; } 21 } 22 //根據不同的HttpMethod方式,獲取請求的參數.如果沒有Encoding對象則使用服務器端默認的編碼. 23 if (request.HttpMethod == "POST") 24 { 25 if (null != destEncode) 26 { 27 Stream resStream = request.InputStream; 28 byte[] filecontent = new byte[resStream.Length]; resStream.Read(filecontent, 0, filecontent.Length); 29 string postquery = destEncode.GetString(filecontent); 30 result = HttpUtility.ParseQueryString(postquery, destEncode); } 31 else 32 { result = request.Form; } 33 } 34 else 35 { 36 if (null != destEncode) 37 { result = System.Web.HttpUtility.ParseQueryString(request.Url.Query, destEncode); } 38 else 39 { result = request.QueryString; } 40 } 41 //返回結果 42 return result; 43 }
另外本方法如果沒有傳遞Encoding或者傳遞的字符串無法轉換成強類型的Encoding對象, 則使用服務器端默認編碼格式(即直接使用Request對象的QueryString和Form獲取參數). 六.Javascript編碼方法 發送請求的一方叫做客戶端.我們經常需要使用Javascript在客戶端編碼中文參數.下面javascript中和編碼有關的函數: 函數名稱 函數說明 解釋 escape() escape() 函數可對字符串進行編碼,這樣就可以在所有的計算機上讀取該字符串。 該方法不會對 ASCII 字母和數字進行編碼,也不會對下面這些 ASCII 標點符號進行編碼: - _ . ! ~ * ' ( ) 。其他所有的字符都會被轉義序列替換。
escape和unescape 在V3版本的標准中已經不在推薦使用.應該用encodeURI和encodeURIComponent方法.對於一個URI, 如果我們希望將它作為完整的網址發送請求, 但是上面帶有中文, 則應該使用encodeURI方法.如果是要編碼參數,則應該使用encodeURIComponent. 下面舉例說明這兩個方法的區別: document.write(encodeURIComponent("http://www.w3school.com.cn")+ "<br />") document.write(encodeURI("http://www.w3school.com.cn")+ "<br />") 結果 http%3A%2F%2Fwww.w3school.com.cn http://www.w3school.com.cn
七.瀏覽器自動編碼 Get請求 對於Get方式發送的請求, 不同的瀏覽器使用不同的編碼方式自動為中文參數編碼. 比如:Firefox/3.0.5 使用UTF-8, IE6使用GB2312. Post請求 對於Post方式發送的請求, 表單中的參數值對是通過request body發送給服務器,此時瀏覽器會根據網頁的ContentType("text/html; charset=GBK")中指定的編碼進行對表單中的數據進行編碼,然后發給服務器。在HTML代碼的Head中添加: <meta http-equiv="Content-Type" content="text/html;charset=gb2312" /> Firefox/3.0.5 會使用根據charset中設置的編碼格式編碼post的中文參數. IE6不起作用. 實驗表明使用客戶端瀏覽器默認編碼格式具有不確定性.所以傳遞中文時我們要手工編碼參數.
總結:
碰到問題應該是去追究本質原因,而不是找到現象就好了,比如第一個方法,就是說我只是將問題解決了,不過根本不知道+號為什么會變成空格的。第二個方案是了解本質原因,根據本質原因處理問題。