在Asp.Net中寫了一個附件上傳和下載的程式,附件上傳到資料庫中,然後將附件的GUID儲存起來,我們可以根據GUID來找到資料庫中的附件,一般附件下載的代碼是:
private void Download(string ID)
{
file = logic.GetAttachmentByID(new Guid(ID));
Response.AddHeader("Content-Type", file.Type);
Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + HttpUtility.UrlEncode(file.FileName) + "\"");
Response.BinaryWrite(file.Data.ToArray());
Response.End();
}
這裡比較重要的就是Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + HttpUtility.UrlEncode(file.FileName) + "\"");這裡需要對中文檔案名稱進行編碼,預設是使用的UTF8編碼。但是編碼後檔案名稱就會變得很長,比如我現在有一個檔案叫:
招標送檢樣機項目檢查登記表(終端)-空.XLS
我們進行網路抓包,可以看到在下載檔案的時候的HTTP響應是:
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 44032
Content-Type: application/vnd.ms-excel
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 12.0.0.6219
X-AspNet-Version: 2.0.50727
Content-Disposition: attachment; filename="%e6%8b%9b%e6%a0%87%e9%80%81%e6%a3%80%e6%a0%b7%e6%9c%ba%e9%a1%b9%e7%9b%ae%e6%a3%80%e6%9f%a5%e7%99%bb%e8%ae%b0%e8%a1%a8(%e7%bb%88%e7%ab%af)-%e7%a9%ba.XLS"
Date: Wed, 25 Mar 2009 08:00:26 GMT
可以得到編碼後檔案名稱變成了:
%e6%8b%9b%e6%a0%87%e9%80%81%e6%a3%80%e6%a0%b7%e6%9c%ba%e9%a1%b9%e7%9b%ae%e6%a3%80%e6%9f%a5%e7%99%bb%e8%ae%b0%e8%a1%a8(%e7%bb%88%e7%ab%af)-%e7%a9%ba.XLS
這都是在HTTP頭裡面的,由於瀏覽器或者其他原因,對於這麼長的HTTP頭,系統會對字串進行截止,那麼就會造成下載的時候檔案名稱不全或者乾脆就是亂碼的情況。我試了一下,這個檔案的下載在IE8裡面是完全正常的,但是在IE6裡面就會造成字串截止,變成“%a0%87送檢樣機項目檢查登記表(終端)-空.XLS”。不同的瀏覽器截止的還不同。
解決辦法有2種,1種是限制使用者上傳的檔案的檔案名稱或者我們在下載的時候寫代碼對檔案名稱進行截止,避免出現亂碼的情況,但是這樣造成的使用者體驗並不好。那就用第2種解決辦法:不使用UTF8的UrlEncode編碼,直接使用gb2312編碼輸出中文名。
具體代碼就是:
protected void Page_Load(object sender, EventArgs e)
{
PostLogic logic = new PostLogic();
if (Request.QueryString["AID"] != null)
{
Response.Clear();
Encoding code = Encoding.GetEncoding("gb2312");
Response.ContentEncoding = code;
Response.HeaderEncoding = code;//這句很重要
Attachment file = logic.GetAttachmentByID(new Guid(Request.QueryString["AID"].ToString()));
Response.AddHeader("Content-Type", file.Type);
Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + file.FileName + "\"");//這裡不進行編碼工作,直接輸出中文字串
Response.BinaryWrite(file.Data.ToArray());
Response.End();
}
}
這樣輸出的就是長中文名了。我們再來抓包看一下HTTP響應的頭:
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 44032
Content-Type: application/vnd.ms-excel
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 12.0.0.6219
X-AspNet-Version: 2.0.50727
Content-Disposition: attachment; filename="招標送檢樣機項目檢查登記表(終端)-空.XLS"
Date: Wed, 25 Mar 2009 09:04:34 GMT
問題就這樣解決了。當然,如果使用者上傳的是一個本來就很長很長的檔案名稱的檔案,那也是沒有辦法的,而且資料庫中設計的欄位可能也沒有那麼長。那就要在上傳的時候做好限制了。