用XMLHTTP实现伪Web服务[Good]

ChinaOk 2002-04-15 06:24:58
加精
本文揭示XMLHTTP的神秘面纱。我很喜欢使用XMLHTTP,主要是因为它能够将任何ActiveX类方法展示给客户。就是说,你能够让客户调用你的ActiveX控件。

===========================================================
本文揭示XMLHTTP的神秘面纱。我很喜欢使用XMLHTTP,主要是因为它能够将任何ActiveX类方法展示给客户。就是说,你能够让客户调用你的ActiveX控件。最主要的是所有的通讯都是在后台进行的。使用XMLHTTP能够扩展对数据库的存取能力。提交查询申请时,用XMLHTTP向ASP侦听(服务)页发出XML格式的指令,ASP网页随即解释该命令并调用VB activeX控件里的方法。这个VB控件用XML字符串形式将查询结果返回给ASP服务页,再由服务页将结果组装成XML格式返回给用户。在作这一系列事情时,不需对当前网页进行重加载。用户甚至不知道后台在作些什么。

在本文末尾可以下载有关示例源程序。

本文示例对系统的要求是:
MS SQL Server(包含pubs数据库示例),
MS IE 5.0+,
MSXML 3.0解析器,
MS IIS - 将示例中所有的ASP文件,CSS,及mybooks.xml文件拷贝到服务器的一个虚路径下。

将bookview.asp, xml_receive.asp, mybooks.xml, default.css, 和book.css等文件拷贝到服务器的一个虚路径下。
在服务器上注册WebClass.xmlcontrol(webclass.dll)。
在xml_receive.asp文件里设置SQL Server服务器名。
在webClass.xmlcontrol类里设置你的用户名和口令。

来看看XMLHTTP的功能:

客户端:这里是bookViewer.asp文件中的一段代码,用XMLHTTP来存取Pubs数据库的books:
var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); //创建XMLHTTP对象
var xmlcmd='<?xml version="1.0"?><ENVELOPE><XMLCMD c1="gettitlesxml" p1="" p2="" p3=""></XMLCMD></ENVELOPE>';
xmlhttp.Open("POST","xml_receive.asp", false); //准备用XMLHTTP向xml_receive.asp发送指令
xmlhttp.Send(xmlcmd); //发出指令

第一行:创建XMLHTTP对象的引用。
第二行:创建XML指令。注意:可以不用XML格式而使用普通文件构造指令。之所以用XML格式,是因为它容易解析指令本身和指令的参数。
第三行:打开连接。其中第一个参数是http方法(最常使用的不是"POST"就是"GET")。第二个参数指向执行指令的URL路径。第三个参数决定是否异步执行。另外还可以加上二个参数,即用户名和口令。在上面的例子中,我用HTTP POST呼叫xml_receive.asp网页(我称它为侦听页),要求同步进行查询工作(在完成查询前不做其他事)。
第四行:发出指令,开始工作。注意:指令是由第二行代码作出的。因为使用了同步执行方式,现在只能坐等结果返回。

侦听页(xml_receive.asp)工作基础
我把这个网页称为侦听页,是因为它在服务端坐等XMLHTTP指令的到来。收到查询请求后,它要做三件事。
首先,将查询请求加载到XML DOM,并对指令及其参数进行解析。
其次,根据客户要求,调用后台Active X控件的处理方法。后台Active X控件将执行结果用XML字符串返回。
第三,将返回结果加载到XML DOM并用Response对象返回给用户。
[译者注:这是一种很典型的三层应用,可以举一反三。]

以上三步骤具体执行如下:

侦听页(第一步 - 指令解析):
以下是xml_receive.asp文件中的一段代码,后面附有注释。这段代码用于解析接收到的查询指令和参数(parameter1, parameter2, parameter3)。参数的数量可以任意增加。

var doc = Server.CreateObject("Msxml2.DOMDocument");
doc.load(Request); //将XMLHTTP请求加载到XML DOM进行解析
var c1=doc.childNodes.item(1).childNodes.item(0).attributes.item(0).text; //指令
var p1=doc.childNodes.item(1).childNodes.item(0).attributes.item(1).text; //参数1
var p2=doc.childNodes.item(1).childNodes.item(0).attributes.item(2).text; //参数2
var p3=doc.childNodes.item(1).childNodes.item(0).attributes.item(3).text; //参数3
if (doc.childNodes.item(1).childNodes.length==2) //检验xml
var passedXML=''+doc.childNodes.item(1).childNodes.item(1).xml;
var xmlreturn=''; //初始化返回值
var doc=null; //释放XML DOM

侦听页(第二步 - 调用后台Active X控件的适当方法):
以下是xml_receive.asp文件中调用"gettitlesxml"方法的一段代码。它创建Active X对象并调用其中的GetTitlesXML()方法来返回Pubs数据库的查询结果。记住,结果是用XML字符串方式返回。

//************* Function gettitlesxml ***********************
if (c1=="gettitlesxml")
{
resultsXML=true; //加载结果的xml字符串
var objWC= Server.CreateObject("WebClass.xmlControl"); //初始化VB控件
objWC.strServer=sqlServer; //指向SQL Server服务器
xmlreturn=objWC.GetTitlesXML(); //VB函数,用XML字符串返回标题
var objWC=null; //释放VB控件
}

侦听页(第三步 - 返回结果):
以下是xml_receive.asp文件中的一段代码,将查询结果返回给用户。这里包括创建结果DOM,加载结果到DOM,检查加载是否正确,最后用ASP的Response对象将结果返回给用户。注意:是用XML DOM的Save方法返回结果,其参数为Response,表示将结果存入Response输出流。

var result = Server.CreateObject("Msxml2.DOMDocument"); //创建结果XML DOM

if (resultsXML) //加载XML字符串
{
result.loadXML(xmlreturn); //调用loadXML将字符串加载到DOM
if (c1=="savemybooks") result.save(Server.MapPath(p1)); //如果需要,保存XML文件
}

if ( result.parseError.errorCode!=0 ) //解析出错
{
//返回结果
xmlreturn='<?xml version="1.0"?><RESULTS error="true">FALSE</RESULTS>';
result.loadXML(xmlreturn); //将出错信息加入到结果
}

//用ASP Response对象将结果返回给用户
Response.ContentType = "text/xml"; //返回XML格式文件
result.save(Response);//将DOM存放到HTTPResponse输出流
var result = null;

返回到客户端(bookViewer.asp)
服务端工作时,客户端只有耐心等待。一旦收到返回结果,就将其加载到XML DOM,并用ASP表单显式。

objSallbooks.load(xmlhttp.responseXML); //将返回值加载到DOM
var xmlhttp = null;
//检验返回是否出错
if (objSallbooks.childNodes.item(1).childNodes.item(0).nodeValue=="FALSE") Snumberofbooks=0;
else Snumberofbooks=(objSallbooks.childNodes.item(1).childNodes.length); //设置Books数量
if (Snumberofbooks>0) display_book(0,1); //显式第一本书籍名

第一行:将XMLHTTP的Response加载到XML DOM对象objSallBooks中去。XMLHTTP另外还有responseText方法用于加载普通文件。
第二行:因为已经建立了XML DOM,可以不再需要XMLHTTP了。
第三行:如果出错,侦听页会返回<?xml version="1.0"?><RESULTS error="true">FALSE</RESULTS>出错信息。
第四行:如果正确,DOM里就有查询结果,并可通过根节点的子节点长度求得结果数量。
第五行:如果有结果,就将结果绑定到表单上显示。

现在可以对gettitlesxml函数作些补充。
对BookViewer.ASP文件作一些改动就能增强gettitlesxml函数的查询功能。用户可以根据书籍的类型,价格和销售日期对书籍进行查询。下面就是改动的代码。注意文本框由原先的只读方式改为常规方式。

var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
var where= "";
if(document.frmFields.Stype.value.length>0) where=where + " type= '"+document.frmFields.Stype.value+"' AND ";
if(document.frmFields.Sprice.value.length>0) where=where + " price<= "+document.frmFields.Sprice.value+" AND ";
if(document.frmFields.Ssales.value.length>0) where=where + " ytd_sales>= "+document.frmFields.Ssales.value;
if(where.length>0) where = " WHERE " + where;
var xmlcmd='<?xml version="1.0"?><ENVELOPE><XMLCMD c1="gettitlesxml" p1="'+where+'" p2="" p3=""></XMLCMD></ENVELOPE>'; xmlhttp.Open("POST", "xml_receive.asp", false); //用XMLHTTP向xml_receive.asp传送指令
xmlhttp.Send(xmlcmd);//发出XML指令

第二行到第六行:建立查询语句
第七行:与原先的代码不同在于增加了一个p1参数,它是由第二行到第七行代码建立的。

xml_receive.ASP文件的改动:
将新增的p1参数加入到Active X控件的GetTitlesXML函数中。

//************* Function gettitlesxml ***********************
if (c1=="gettitlesxml")
{
resultsXML=true; //加载结果的xml字符串
var objWC= Server.CreateObject("WebClass.xmlControl"); //初始化VB控件
objWC.strServer=sqlServer; //指向SQL Server服务器
xmlreturn=objWC.GetTitlesXML(p1); //VB函数,用XML字符串返回结果
var objWC=null; //释放VB控件
}

结语
这里所作的一切是为了将ASP的客户互动应用技术提高一个档次。用户能够在一个简单的网页里访问数据库。查询过程由XMLHTTP在后台执行,给用户的感觉就象在用一个Windows程序而不是Web应用。本文涉及的是Web服务理念。比Web服务更为复杂的是SOAP协议,它能使Web服务更具有弹性。在一般情况下 (只要不是分布式应用),用上面给出的方法是足够的了。

按照上面描述的技术路线:
 客户端应用-->ASP侦听页-->Active X控件,以及Active X控件-->ASP侦听页-->客户端应用
提供的方法,可以在客户端和后台Active X控件之间建立通讯联系。ASP的侦听页可以给出用户需要的Active X控件的部分方法和属性,而将其他内容隐藏起来。在侦听页中可以建立加密机制。这样可以使得整个数据库安全性得到很大程度的提高。因为所有对数据库的访问都是通过Active X
...全文
80 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
sunbeamy 2002-04-15
  • 打赏
  • 举报
回复
只有这样前后台才能彻底分离,不是讨论做不做的到。
自打看见xmlhttp以后,不用form已经很久了......

Lostinet 2002-04-15
  • 打赏
  • 举报
回复
其实做好点,就算是HTTPGET,HTTPPOST也可以做。
Lostinet 2002-04-15
  • 打赏
  • 举报
回复
其实我想过,不用COM也可以实现SOAP的。
假设服务器已经有WEBSERVICE,
那么只要我们在客户端用脚本(JScript)解析WDSL,然后分配对象,就可以模拟SOAPCLIENT了。
例如我期望的写发是:
try{
var ws=new WebClass("http://host.com/webservice.aspx?WDSL");
}catch(x){
...failed...
return;
}

try{
ws.WebMothed1("str1","str2");
}catch(x){
...failed...
return;
}

我的具体想法是:
function WebClass(urlWDSL)
{
..获取WDSL的信息
if(WDSL中不支持SOAP)
//没有办法啦。。难道每调用一次都要提交一个FORM?
throw(new Error(-1,"不支持SOAP"));
..处理WEBMETHOD的信息生成webmethods
例如现在有[WebMothod]string MD5(string strInput)
那么就:
for(var i=0;i<webmethods.length;i++)
{
var curwm=this[webmethods[i].name]=function()
{
var fs=function(fs)
{
return fs.caller;
}
var fs=fs(fs);
return fs.Invoke(this,fs,fs.webmethoddata,fs.arguments);
}
curwm.webmethoddata=webmethods[i]
curwm.Invoke=function(ws,wm,wmdata,args)
{
根据wmdata提供的信息,检查args和进行可行的转换
遇到不可以转换的,就开始发送:
xmlhttp.Open("POST",wmdata.urlSoap,false)//同步
xmlhttp.setRequestHeader....
xmlhttp.Send...
然后把结果进行处理。
如果是有效的结果,返回结果(转换)。
如果不是有效的,抛出异常
}
}
}
--------------
希望有人和我讨论。
lostinet@chongjian.com

8,906

社区成员

发帖
与我相关
我的任务
社区描述
XML/XSL相关问题讨论专区
社区管理员
  • XML/XSL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧