概述
本文說明了一個使用XML技術上傳檔案的例子,使用該方法沒有傳統方法中的種種限制。 這個範例講述如何使用MSXML3.0和ADO Stream物件來實作這種新的上傳方法。好處很多,例如,不需要專用的上傳元件。
引言
為了在HTML網頁中獲得上傳功能,在客戶端我們可以使用以下格式的FORM:
<FORM NAME="myForm"
ACTION="TargetURL.asp"
ENCTYPE="multipart/form-data"
METHOD="post">
<INPUT TYPE="file" NAME="myFile">
<INPUT TYPE="submit" VALUE="Upload File">
</FORM>
這種方案在客戶端和伺服器端的使用都有許多限制。首先,我們必須使用POST方法,因為GET方法無法處理這樣的表單資料。而且,沒有任何方法可以在不使用表單的情況下引發一個POST動作。把資料傳送給表單處理程序後,瀏覽器會將處理程序作為新頁面加載,然後使用者會看到一個不討人喜歡的頁面轉換過程。
ENCTYPE屬性為表單定義了MIME編碼方式,上傳檔案的表單的ENCTYPE屬性必須使用「multipart/form-data」。把這個屬性設定為「multipart/form-data」就建立了一個與傳統結構不同的POST緩衝區(複合結構),ASP的Request物件無法存取這樣的表單內容。所以,我們可以使用Request.binaryRead方法來存取這些數據,但無法使用腳本語言來完成這一切。 Request.binaryRead方法傳回一個VTarray型資料(只包含無符號一位元組字元的Variant型陣列)。但是腳本語言只能處理Variant型資料。為了解決這個問題,只能使用專用的ASP上傳元件,或是ISAPI擴充程序,例如CPSHOST.DLL。這是設計上的限制。
新的上傳方案
需要依照下列步驟操作。
客戶端:
使用MSXML 3.0建立一個XML文件建立一個針對二進位內容的XML節點使用ADO Stream object將上傳的檔案資料放入該節點使用XMLHTTP物件把這個XML文件傳送給Web伺服器
伺服器端:
從Request物件中讀出XML文件讀出二進位節點中的資料並且儲存到伺服器上的檔案。當然,我們也可以將其儲存到資料庫的BLOB型欄位中。
在解釋這段程式碼之前,我們可以對這個方案做一些思考。
對XML的思考
XML格式支援許多資料類型,例如numeric, float, character等等。很多作者將XML定義為ASCII格式,但是我們不能忽視,XML技術還可以使用「bin.base64」資料型別來描述二進位資訊。這個特性在MS XML3.0解析器重得到完全的支持,但目前還需要一些特別設定。這個物件提供一些可以對二進位資料進行完全控制的屬性:
obj_node.dataType - 這個可讀寫的屬性定義了特定節點的資料類型。 MSXML解析器支援更多的資料類型(請參閱MSDN:http: //msdn.microsoft.com/library/psdk/xmlsdk/xmls3z1v.htm )
對於二進位數據,我們可以使用“bin.base64”類型。
obj_node.nodeTypedValue - 此可讀寫屬性包含了依照製定類型表示的指定節點的資料。
我們可以建立一個包含多個bin.base64類型節點的XML文檔,節點中包含上傳的文件。這點特性可以使用一個POST一次上傳多個檔案。
我們可以使用XMLHttpRequest物件和POST方法傳送一個XML文件給Web伺服器。該物件為HTTP伺服器提供了客戶端協定支持,允許在Web伺服器上傳送和接受MS XMLDOM物件。 XMLHttpRequest是Internet Explorer 5內建的COM物件(不需要客製化安裝),且傳送完畢後無需轉換頁面。
對ADO Stream物件的思考
我們可以在客戶端建立一個包含一個或多個二進位節點的XML文件。我們也必須把檔案內容填入節點中。但很不幸,腳本語言不能存取本機檔案系統,而且Scripting.FileSystem物件(是Win32系統的內建物件)到目前為止還不能存取二進位檔案。這是設計上的限制。所以我們需要另外找一個可以提供對本地二進位檔案的存取的COM物件。
ADO Stream物件(MDAC 2.5中的元件)提供了讀取、寫入和管理二進位流資料的手段。位元組流的內容可以是文本,或二進位數據,並且沒有容量上的限制。在ADO 2.5中,Microsoft對Stream物件的介紹不屬於ADO物件結構的任何一層,所以,我們無需捆綁即可使用該物件。
本文使用Stream物件存取文件內容,再把內容存入XML節點。
用戶端
以下範例程式碼使用Stream和MSXML物件完成檔案上傳動作。
<HTML>
<HEAD><TITLE>File Send</TITLE></HEAD>
<BODY>
<INPUT id=btn_send name="btn_send" type=button value="FILE SEND">
<DIV id=div_message>Ready</DIV>
</BODY>
</HTML>
<SCRIPT LANGUAGE=javascript>
// 上傳函數
function btn_send.onclick()
{
// 建立ADO-stream 對象
var ado_stream = new ActiveXObject("ADODB.Stream");
// 建立包含預設頭資訊和根節點的XML文檔
var xml_dom = new ActiveXObject("MSXML2.DOMDocument");
xml_dom.loadXML('<?xml version="1.0" ?> <root/>');
// 指定資料型
xml_dom.documentElement.setAttribute("xmlns:dt", "urn:schemas-microsoft-com:datatypes");
// 建立一個新節點,設定為二進位資料節點
var l_node1 = xml_dom.createElement("file1");
l_node1.dataType = "bin.base64";
// 開啟Stream對象,讀取來源文件
ado_stream.Type = 1; // 1=adTypeBinary
ado_stream.Open();
ado_stream.LoadFromFile("c:\tmp\myfile.doc");
// 將文件內容存入XML節點
l_node1.nodeTypedValue = ado_stream.Read(-1); // -1=adReadAll
ado_stream.Close();
xml_dom.documentElement.appendChild(l_node1);
// 可以建立多個二進位節點,一次上傳多個檔案
// 把XML文件傳送到Web伺服器
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.open("POST","./file_recieve.asp",false);
xmlhttp.send(xml_dom);
// 顯示伺服器傳回的訊息
div_message.innerHTML = xmlhttp.ResponseText;
}
</SCRIPT>
伺服器端
以下程式碼使用相同的物件提供伺服器端的上傳處理功能。
<%@ LANGUAGE=VBScript%>
<% Option Explicit
Response.Expires = 0
' 定義變數和物件。
dim ado_stream
dim xml_dom
dim xml_file1
' 建立Stream 對象
set ado_stream = Server.CreateObject("ADODB.Stream")
' 從Request物件建立XMLDOM對象
set xml_dom = Server.CreateObject("MSXML2.DOMDocument")
xml_dom.load(request)
' 讀出包含二進位資料的節點
set xml_file1 = xml_dom.selectSingleNode("root/file1")
' 開啟Stream對象,把資料存入其中
ado_stream.Type = 1 ' 1=adTypeBinary
ado_stream.open
ado_stream.Write xml_file1.nodeTypedValue
' 檔案記憶體
ado_stream.SaveToFile "c:tmpupload1.doc",2 ' 2=adSaveCreateOverWrite
ado_stream.close
' 銷毀對象
set ado_stream = Nothing
set xml_dom = Nothing
' 向瀏覽器傳回訊息
Response.Write "Upload successful!"
%>
也可以使用Stream物件把資料放到資料庫的BLOB型欄位。
使用該方法的益處
不會引起頁面轉換。
不需要專用組件。
可同時上傳多個文件。
這段程式是純腳本寫成的,可以很容易的插入到其他程式碼中,而不需要任何HTML物件的配合。還可以把這個邏輯在任何支援COM標準的語言中實作。
系統安全考慮
該方法只能使用於內部網絡,因為它需要IE5的安全等級設定為「低」。必須:
允許腳本和ActiveX物件。此設定允許瀏覽器執行類似"myobj = new activexobject(...)"的JScript語句;
必須允許穿越網域存取資料來源。這個設定允許在客戶端使用Stream物件。也必須在伺服器和客戶端都安裝MS XML DOM 3.0 和MDAC 2.5 。