http://blog.csdn.net/Beerium/archive/2006/04/04/650103.aspx
一、數據庫遠程管理技術
基於互聯網的廣域網現代應用中的一個重要環節是數據庫遠程監控。首先簡單回顧一下互聯網上的數據庫遠程管理技術的發展過程和方式:
早期通過編寫CGI-BIN程序模塊進行數據庫遠程管理。但CGI-BIN的運行速度慢,維護很不方便,現在已經基本被棄用。
這幾年使用組件對象模型(Component Object Model, COM)的應用非常多,效果也很好。但如果使用的是第三方服務器(筆者的網站就是建立在第三方的虛擬主機上),服務器方往往因爲保密或其它商業原因不允許用戶註冊自己的組件。
近年來由微軟公司推出的.NET平臺和SUN公司的J2EE平臺都是非常高檔的數據庫遠程管理與服務平臺。都能提供優質的多層(n-Tier)應用服務。
其中,.NET的簡單對象訪問協議(Simple Object Access Protocol, SOAP)使用超文本傳輸協議(Hypertext Transfer Protocol, HTTP)和擴展標記語言(Extensible Markup Language, XML)技術實現跨系統(例如Windows - Linux)的通訊服務方式已經廣爲開發商接受和使用。許多大型應用,例如企業資源計劃(Enterprise resource planning, ERP)等都建立在這樣的大型平臺之上。
但對於中小型應用,比如一個網站的建設和維護,這種大型應用平臺就顯得有些尾大不掉,開銷也過於龐大。
曾經在互聯網技術和Java技術方面一度落後的微軟公司在XML應用開發則走在了前頭。她的XML解析器(MSXML)中的XMLHTTP協議是一個非常方便實用的客戶/服務通訊管道。綜合運用XMLHTTP以及ActiveX數據對象(ActiveX Data Objects, ADO/ADOX)可以簡單方便地實現數據庫遠程管理。
本文介紹如何綜合運用XMLHTTP和ADO/ADOX進行遠程數據庫管理。
二、數據庫遠程管理體系
數據庫遠程管理的任務流程是:
1、客戶端向服務端發出數據庫結構和數據的查詢或修改指令。
2、服務端接受並執行有關指令並向客戶端返回結果。
3、客戶端接受並顯示服務端返回的指令執行結果。
實現數據庫遠程管理的二個主要關鍵環節是:
1、客戶端與服務端之間的指令上傳和結果下傳的數據通道,由XMLHTTP協議實現。
2、服務端前沿與數據庫之間的指令傳送和結果返回,由起着中間層作用的ADO/ADOX接口完成。
三、XMLHTTP的使用
顧名思義,XMLHTTP是個傳送XML格式數據的超文本傳輸協議。
實際上,XMLHTTP的數據傳輸過程更爲靈活一些:
它上傳的指令可以是XML格式數據,也可以是字符串,流,或者一個無符號整數數組。還可以是URL的參數。
它下達的結果可以是XML格式數據,也可以是字符串,流,或者一個無符號整數數組。
詳情可參閱文末鏈接。
客戶端調用XMLHTTP的過程很簡單,只有5個步驟:
1、創建XMLHTTP對象
2、打開與服務端的連接,同時定義指令發送方式,服務網頁(URL)和請求權限等。
客戶端通過Open命令打開與服務端的服務網頁的連接。與普通HTTP指令傳送一樣,可以用"GET"方法或"POST"方法指向服務端的服務網頁。
3、發送指令。
4、等待並接收服務端返回的處理結果。
5、釋放XMLHTTP對象
XMLHTTP方法:
Open bstrMethod, bstrUrl, varAsync, bstrUser, bstrPassword
bstrMethod:數據傳送方式,即GET或POST。
bstrUrl:服務網頁的URL。
varAsync:是否異步執行。缺省爲True,即異步執行,但只能在DOM中實施異步執行。 應用中一般將其置爲False,即同步執行。
bstrUser:用戶名,可省略。
bstrPassword:用戶口令,可省略。
Send varBody
varBody:指令集。可以是XML格式數據,也可以是字符串,流,或者一個無符號整數數組。也可以省略,讓指令通過Open方法的URL參數代入。
setRequestHeader bstrHeader, bstrValue
bstrHeader:HTTP 頭(header)
bstrValue:HTTP 頭(header)的值
如果Open方法定義爲POST,可以定義表單方式上傳:
xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
另外的一些方法:
abort
取消當前 HTTP 請求
getAllResponseHeaders
從響應信息中檢索所有的標頭字段
getResponseHeader
從響應信息正文中獲得一個 HTTP 標頭值
XMLHTTP屬性:
onreadystatechange:在同步執行方式下獲得返回結果的事件句柄。只能在DOM中調用。
readyState Long 異步操作的狀態:未初始化(0),正在加載(1),已加載(2),交互(3),已完成(4)
responseBody:Variant 結果返回爲無符號整數數組。
responseStream:Variant 結果返回爲IStream流。
responseText :string 結果返回爲字符串。
responseXML: object結果返回爲XML格式數據。
status Long 服務器返回的HTTP狀態碼
statusText String 服務器HTTP響應行狀態
下面是本文附件源程序中的一個應用示例:
Function GetResult(urlStr)
Dim xmlHttp
Dim retStr
Set xmlHttp = CreateObject("Msxml2.XMLHTTP") '創建對象
On Error Resume Next '出錯處理
xmlHttp.Open "POST", urlStr, False '用POST方式打開連接,異步執行。
xmlHttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" '上傳表單
xmlHttp.Send '發送指令
If Err.Number = 0 Then '如果連接正確
retStr = xmlHttp.responseText '等待並獲得服務端返回的結果字符串
Else
retStr = "Url not found" '否則返回出錯信息
End If
Set xmlHttp = nothing '釋放對象
GetResult = retStr '返回結果
End Function
GetResult()函數帶入一個服務網頁的URL參數,把上傳的指令安放在URL後面的參數上,如:
urlStr = "server.asp?cmd=" & cmd & "&db=" & db & "table=" & table
cmd:執行方式,例如查詢,修改,刪除等等。
db:服務端數據庫名
table:服務端表名
然後提交指令,等待並接收返回的處理結果。結果以字符串方式返回。
最後由函數調用者處理並顯示結果。
使用何種數據類型?
正如上面所說,通過 XMLHTTP 通道傳送的數據可以有很多種類型。其中用的最多的是 XML DOM 和 STRING。
選用何種數據類型取決於程序的需要。
爲了從服務器取得數據,客戶端和服務器都使用 XML 數據是一個很好的方法。因爲這樣可以處理大量的數據,請求服務器添加/刪除/修改/查詢 記錄,或在客戶端排序/過濾數據。
本文的目的是爲了在虛擬主機上遠程管理數據庫,所以這需要有如下兩個功能:
1. 遠程管理數據庫:添加/刪除/修改/查詢 遠程數據庫/表/字段。
2. 遠程管理數據庫中的數據: 添加/刪除/修改/查詢 記錄
所以這裏我們使用 XMLHTTP 來發送/接受 字符串
這樣做的好處很明顯:可以無閃爍刷新頁面
由於是採用字符串, 所以可以簡單的使用 "Response.Write" 來返回結果。一旦服務器 response 完畢,客戶端用 "xmlHttp.responseText" 方法來獲取整個結果,並返回給調用者,用於刷新頁面數據。
如果採用異步方式,則客戶端按下按鈕後,會有一定的延時,客戶端必須等待返回數據。如果採用異步或使用 XML DOM 則可以避免這一點。
Using ADOX
ADO 不能用來遠程管理數據庫,我們可以使用 ADOX。
ADOX 是 ADO 的擴展, 它提供了更多的函數用於處理數據庫。一旦通過身份認證,並且你的角色爲數據庫管理員,那麼你可以通過 ADOX 作任何操作。
This sample requests:
生成動態的 select 菜單,顯示指定路徑下的數據庫名。
生成動態的 select 菜單,顯示上述菜單中選定的數據庫中的表名。
根據選定的數據庫和表,動態的列出字段名。
根據虛擬目錄路徑的改變和 select 的改變,即時的改變顯示的內容而且無閃爍的刷新頁面。
使用 Scripting.FileSystemObject 獲得給定路徑的數據庫名。 使用 ADOX 獲取表名和字段名。代碼如下:
獲取一個數據庫中的表名:
Sub GetTables_Server(DBName)
Dim i
Dim catDB ’ADODB.Catalog 對象
Set catDB = Server.CreateObject("ADOX.Catalog") ’創建 ADODB.Catalog 對象
On Error Resume Next ’錯誤處理
catDB.ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Server.MapPath(DBName) ’打開連接
’如果需要可加上用戶名和密碼
If Err.Number = 0 Then ’成功
’ 動態產生 select 選單
Response.Write "<select name=’selTable’ onChange=ShowResult(’fields’)>"
With catDB
For i = 0 To .Tables.Count -1
If .Tables(i).Type = "TABLE" then ’ 如果是一個表
’將表名添加到 select
Response.Write "<option value=" & .Tables(i).Name & ">" &_
.Tables(i).Name &"</option>"
End If
Next
End With
Response.Write "</select>" ’ select 輸出完畢
Else
’錯誤信息
Response.Write "錯誤: 不能打開數據庫 - " & DBName
End If
Set catDB = Nothing ’ 釋放 ADODB.catalog 對象
End Sub
獲取表中的字段名:
Sub GetFields_Server(dbName, tableName)
Dim i, j
Dim catDB ’ADODB.Catalog 對象
Set catDB = Server.CreateObject("ADOX.Catalog") ’創建 ADODB.catalog 對象
On Error Resume Next ’錯誤處理
catDB.ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Server.MapPath(dbName) ’打開連接
’如有必要在此添加用戶名和密碼
If Err.Number = 0 Then ’ 成功
’找到匹配的表名
With catDB
For j = 0 To .Tables.Count -1
If (.Tables(j).Type = "TABLE") and (.Tables(j).Name = tableName) Then
Exit For
End If
Next
End With
’列出字段名
With catDB.Tables(j)
For i = 0 To .Columns.Count -1
’如果是主鍵,選中之
If .Columns(i).Properties("Autoincrement") = True Then
Response.Write "<input type=’radio’ name=’field’ value=" &_
.Columns(i).Name & " checked=true>" & .Columns(i).Name & ""
’顯示字段名
Else
Response.Write "<input type=’radio’ name=’field’ value=" &_
.Columns(i).Name & ">" & .Columns(i).Name & ""
’顯示字段名
End If
Next
End With
Else
’Error message
Response.Write "錯誤: 不能打開數據庫 - " & dbName
End If
Set catDB = Nothing ’ 釋放 ADODB.catalog 對象
End Sub
注:本例中所有的表採用了自增字段作爲主鍵。如果你的數據庫中未採用自增字段作爲主鍵或未指定主鍵,則需要重寫上述代碼。使用自增字段作爲主鍵是一個很好的習慣。
補充資料:js版本
MSXML中提供了Microsoft.XMLHTTP對象,能夠完成從數據包到Request對象的轉換以及發送任務。
創建XMLHTTP對象的語句如下:
Set objXML = CreateObject("Msxml2.XMLHTTP") 或
Set objXML = CreateObject(“Microsoft.XMLHTTP”)
’ Or, for version 3.0 of XMLHTTP, use:
’ Set xml = Server.CreateObject("MSXML2.ServerXMLHTTP")
對象創建後調用Open方法對Request對象進行初始化,語法格式爲:
poster.open http-method, url, async, userID, password
Open方法中包含了5個參數,前三個是必要的,後兩個是可選的(在服務器需要進行身份驗證時提供)。參數的含義如下所示:
http-method: HTTP的通信方式,比如GET或是 POST
url: 接收XML數據的服務器的URL地址。通常在URL中要指明 ASP或CGI程序
async: 一個布爾標識,說明請求是否爲異步的。如果是異步通信方式(true),客戶機就不等待服務器的響應;如果是同步方式(false),客戶機就要等到服務器返回消息後纔去執行其他操作
userID 用戶ID,用於服務器身份驗證
password 用戶密碼,用於服務器身份驗證
XMLHTTP對象的Send方法
用Open方法對Request對象進行初始化後,調用Send方法發送XML數據:
poster.send XML-data
Send方法的參數類型是Variant,可以是字符串、DOM樹或任意數據流。發送數據的方式分爲同步和異步兩種。在異步方式下,數據包一旦發送完畢,就結束Send進程,客戶機執行其他的操作;而在同步方式下,客戶機要等到服務器返回確認消息後才結束Send進程。
XMLHTTP對象中的readyState屬性能夠反映出服務器在處理請求時的進展狀況。客戶機的程序可以根據這個狀態信息設置相應的事件處理方法。屬性值及其含義如下表所示:
值 說明
0 Response對象已經創建,但XML文檔上載過程尚未結束
1 XML文檔已經裝載完畢
2 XML文檔已經裝載完畢,正在處理中
3 部分XML文檔已經解析
4 文檔已經解析完畢,客戶端可以接受返回消息
客戶機處理響應信息
客戶機接收到返回消息後,進行簡單的處理,基本上就完成了C/S之間的一個交互週期。客戶機接收響應是通過XMLHTTP對象的屬性實現的:
● responseTxt:將返回消息作爲文本字符串;
● responseXML:將返回消息視爲XML文檔,在服務器響應消息中含有XML數據時使用;
● responseStream:將返回消息視爲Stream對象
------就是下面這個很簡單的JAVASCRIPT函數SEND(STR,URL)---------------
使用到的是XMLDOM和XMLHTTP對象.用這種技術的好處是:全JS控制,方便/簡單,比RDS
或者remote好多了.(前提:服務器端和客戶端都必須安裝IE5或者更高版本),在俺貼的
那個無刷新在線信息功能使用的也是這種技術.有興趣的朋友可以看看..
function Send(Str,URL)
//STR參數是傳入的XML數據,你也可以傳入其他文本數據.
//不過這個函數需要服務器端處理之後返回XML數據,你也可以修改一下
//URL參數表示你所要處理數據的ASP文件地址
{
var Http = new ActiveXObject("Microsoft.XMLHTTP") //建立XMLHTTP對象
var Dom = new ActiveXObject("Microsoft.XMLDOM") //建立XMLDOM對象
Http.open("POST",URL,false)
//第一個參數的意思是,用"POST"方式發送數據.可以大到4MB,也可以換爲"GET".只能256KB
//第2個參數的意思是數據發送到哪個文件處理
//第3個參數意思是同步或異步方式.TRUE爲異步,FALSE爲同步
Http.send(Str) //開始發送數據.............嘟嘟..
Dom.async=false //設置爲同步方式獲取數據
Dom.loadXML(Http.responseText)
//開始獲取服務器端處理後返回的數據.我在這裏設置必須爲XML數據,否則出錯.
//你也可以自己修改.使返回的是2進制或者記錄集數據.................................
if(Dom.parseError.errorCode != 0) //檢查是否發生獲取數據時錯誤
{
delete(Http)
delete(Dom)
return(false)
}
else
{
var Back = Dom.documentElement.childNodes.item(0).text
//得到返回的XML數據,我這裏假設處理程序只返回一行XML數據(一個節點)
delete(Http)
delete(Dom)
return(Back) //函數返回數據.......................結束
}
}
VAR CAT = Send("<用戶資料><姓名>謝檸檬</姓名></用戶資料>","HTTP://WWW.CHINAASP.COM/VIVA.ASP") //執行函數
IF(CAT == FALSE)
{
ALERT("對不起.處理程序返回的是FALSE.數據處理已經失敗........")
}
ELSE
{
IF(EVAL(CAT))
{
ALERT("OK.數據已經發送成功.兼以處理完成!!!!!!")
}
ELSE
{
ALERT("對不起.處理程序返回的是FALSE.數據處理已經失敗........")
}
}
===============================VIVA.ASP============================
ON ERROR RESUME NEXT
DIM BOBO
DIM MOMO
SET BOBO = SERVER.CREATEOBJECT("MICROSOFT.XMLDOM")
BOBO.ASYNC = FALSE
BOBO.LOAD REQUEST
IF BOBO.PARSEERROR.ERRORCODE <> 0 THEN
RESPONSE.WRITE("<程序處理結果><最終結果>FALSE</最終結果></程序處理結果>")
ELSE
SET MOMO = BOBO.DOCUMENTELEMENT
IF MOMO.CHILDNODES.ITEM(0).TEXT = "謝檸檬" THEN
RESPONSE.WRITE("<程序處理結果><最終結果>TRUE</最終結果></程序處理結果>")
ELSE
RESPONSE.WRITE("<程序處理結果><最終結果>FALSE</最終結果></程序處理結果>")
END IF
END IF
SET BOBO = NOTHING
下面是個實際應用的例子
<%
Dim objXMLHTTP, xml
Set xml = Server.CreateObject("Microsoft.XMLHTTP") ’創建對象
xml.Open "GET","http://www.pconline.com.cn/pcedu/empolder/wz/xml/0404/366680.html",False ’ ’設置對象,具體xmlhttp詳細使用方法請見:http://www.cnsxml.com/blogview.asp?logID=273 ; 《XMLHTTP 對象及其方法》一文
xml.Send ’發送請求
Response.AddHeader "Content-Disposition", "attachment;filename=mitchell-pres.zip" ’添加頭給這個文件
Response.ContentType = "application/zip" ’設置輸出類型
Response.BinaryWrite xml.responseBody ’輸出二進制到瀏覽器
response.
Set xml = Nothing
%>
XMLHttpRequest的同步和異步請求
客戶端利用XMLHTTP發送請求得到服務端應答數據,並用Javascript操作DOM最終更新頁面- 又稱無刷新更新頁面,有代替傳統web開發中採用form(表單)遞交方式更新web頁面的趨勢。
XMLHTTP依賴於XMLHttpRequest完成從客戶端的請求到服務端的應答。XMLHttpRequest提供了兩個方法open和send。open方法用於初始化XMLHttpRequest
對象、指示請求的方式(get、post等)、安全性連接等,在調用open方法後必須調用send方法發送Http Request(Http請求)以返回Http Reponse(Http應答)。
看MSDN中對send方法的簡介:
This method is synchronous or asynchronous, depending on the value of the bAsync parameter in the open call. If open is called with bAsync == False, this call does not return until the entire response is received or the protocol stack times out. If open is called with bAsync == True, this call returns immediately.
send方法是否同步或異步工作取決於open方法中的bAsync參數,如果bAsync == False表示send方法工作在同步狀態下,發送http請求後,只有當客戶端接收到來自服務端的全部應答數據或協議棧超時返回!反之bAsync == True,工作在異步狀態下,直接返回。
實際運用中,設置bAsync = True, 使send方法被調用後XMLHttpRequest工作在異步狀態,如果設爲同步狀態可能會導致不必要的長時間等待!
另外,無論在同步或異步請求工作狀態下,XMLHttpRequest如何得到由服務端返回的應答數據?
看下面的示例代碼:
<script>
var xmlhttp=null;
function PostOrder(xmldoc)
{
varxmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
xmlhttp.Open("POST", "http://myserver/orders/processorder.asp", false);
xmlhttp.onreadystatechange= HandleStateChange;
xmlhttp.Send(xmldoc);
}
function HandleStateChange()
{
if (xmlhttp.readyState == 4)
{
alert("Result = " + xmlhttp.responseXML.xml);
}
}
</script>
服務端返回應答數據並完全被加載, 可通過XMLHttpRequest屬性readState獲知,其值變爲4 - COMPLETED (已加載完成),
當readState變化時會調用XMLHttpRequest對象中的回調函數onreadstatechange,在函數中驗證xmlhttp.readyState == 4,
這裏得到的是XML文檔(如果服務端有返回xml文檔數據).
通過xmlHttp和ASP的結合,我們可以輕鬆完成網頁的異步調用。
代碼如下:
1.新建Display.asp(這是前臺顯示頁面)
注意xmlhttp.readyState的4個屬性
1:LOADING;2:LOADED;3:INTERACTIVE;4:COMPLETED
<%@ Language=VBScript %>
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
</HEAD>
<script language="javascript">
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
function fnDo(ID)
{
var xmlDom = new ActiveXObject("Msxml2.DOMDocument");
var strURL = "GetInfo.asp?ID=" + ID;
xmlhttp.Open("POST",strURL , true);
xmlhttp.onreadystatechange = fnRun;
xmlhttp.Send(xmlDom);
divTest.innerHTML = "Loading..."
}
//--------------------------------------------------------
function fnRun()
{
var state = xmlhttp.readyState;
var xmlDom = new ActiveXObject("Msxml2.DOMDocument");
if (state == 4)
{
xmlDom.loadXML(xmlhttp.responseXML.xml);
//alert(xmlDom.documentElement.selectSingleNode("//objXML").text)
var getInfo = xmlDom.documentElement.selectSingleNode("//objXML").text;
divTest.innerHTML = getInfo
}
}
</script>
<BODY>
<input type=button value="異步調用" οnclick="fnDo(document.all.txtInput.value)">
<input type=text id=txtInput>
<DIV id=divTest></DIV>
<P> </P>
</BODY>
</HTML>
2.在建立GetInfo.asp(這是後臺處理頁面)
<%
Dim sID,objResult
sID = Trim(Request("ID"))
’sID = 28
Set objResult = Server.CreateObject("MSXML2.DOMDocument")
objResult.loadXML ("<objXML></objXML>")
’**************************************************************
’**************************************************************
objResult.selectSingleNode("objXML").text = "Get:" & sID
Response.ContentType = "text/xml"
objResult.save (Response)
Response.End
Set objSch = Nothing
Set objResult = Nothing
%>
3.運行Display.asp頁面,在文本框裏輸入內容,點擊按鈕,可以看到Loading的提示,隨後在不刷新頁面的情況下得到了文本框裏的內容。當然你也可以在GetInfo.asp那個頁面里根據發送的參數做一些複雜的出來,隨後把結果返回出來。
XmlHttp異步獲取網站數據的例子(孟子E章)
文檔提供者:newebug () 於 2005-3-15
<script>
var oDiv
var xh
function getXML()
{
oDiv = document.all.m
oDiv.innerHTML = "正在裝載欄目數據,請稍侯......."
oDiv.style.display= ""
xh = new ActiveXObject("Microsoft.XMLHTTP")
xh.onreadystatechange = getReady
xh.open("GET",a.value,true)
xh.send()
}
function getReady()
{
if(xh.readyState==4)
{
if(xh.status==200)
{
oDiv.innerHTML = "完成"
}
else
{
oDiv.innerHTML = "抱歉,裝載數據失敗。原因:" + xh.statusText
}
}
}
</script>
<body>
xmlhttp異步的例子:
URL:<input name=a value="http://www.microsoft.com" style="width:600px">
<input οnclick="getXML()" type="button" value="得到源代碼">
<input οnclick="if(xh && xh.responseText) {alert(xh.responseText);oDiv.innerHTML=xh.responseText}" type="button" value="顯示源代碼">
<div id=m></div>