XmlHttpRequest调用Webservice的一点心得
2012-07-18 18:08
357 查看
因为项目需要,以后前端、手机客户端调用ASP.NET的Webservice来获取信息.所以这段时间开始看Webservice,试着通过XmlHttpRequest调用Webservice,过程中碰到不少问题,也有不少的收获。
首先,因为JSON对于JS的便利性,考虑通过JSON来请求和返回数据。在JS中实例化一个xmlHttpRequest对象,然后根据网上的说明POST的地址为:asmx页面地址/Web方法名。在RequestHeader中设置Content-Type为application/json;charset=utf-8,SOAPAction设为Web方法名。Web方法的参数用JSON格式send出去。
代码如下:
比如请求调用Webservice1中的HelloWorld方法:
调用前请记得把Webservice1上面的[System.Web.Script.Services.ScriptService]取消注释,调用后可以看到弹出警告窗口:{"d":"HelloWorld"}。把Content-Type设为text/xml时,警告窗口的内容变就变成了<?xmlversion="1.0"encoding="utf-8"?><stringxmlns="http://tempuri.org/">HelloWorld</string> 。
这时候虽然参数“{}”还是JSON的形式请求却是XML格式,但因为HelloWorld没有参数,所以忽略了内容的格式,能够正常返回值。
如果修改服务端的HelloWorld方法,添加一个string类型的参数somebody。
将请求端的Content-Type改回application/json,传送参数改为{"somebody":"Krime"},调用后弹出窗口内容变为{d:"HelloWorld&Hello,Krime!"}。
但如果这时再直接把Content-Type改为text/xml,调用后服务器将会报错:System.InvalidOperationException:请求格式无效:text/xml;charset=UTF-8。在System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()在System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()
于是我们把参数格式也修改一下,按照Webservice调试页面的示例,将参数改为:
首先,因为JSON对于JS的便利性,考虑通过JSON来请求和返回数据。在JS中实例化一个xmlHttpRequest对象,然后根据网上的说明POST的地址为:asmx页面地址/Web方法名。在RequestHeader中设置Content-Type为application/json;charset=utf-8,SOAPAction设为Web方法名。Web方法的参数用JSON格式send出去。
代码如下:
functiongetXmlHttp(){ varxmlHttp; if(window.XMLHttpRequest) {//codeforIE7+,Firefox,Chrome,Opera,Safari xmlHttp=newXMLHttpRequest(); } else {//codeforIE6,IE5 xmlHttp=newActiveXObject('Microsoft.XMLHTTP'); } returnxmlHttp; } functionwebservice(url,action,data,success,error,complete,failed){ varxmlHttp=getXmlHttp();//获取XMLHttpRequest对象 xmlHttp.open('POST',url+'/'+action,true);//异步请求数据 xmlHttp.onreadystatechange=function(){ if(xmlHttp.readyState==4){ try{ if(xmlHttp.status==200&&typeof(success)=='function'){ success(xmlHttp.responseText); } elseif((xmlHttp.status/100==4||xmlHttp.status/100==5)&&typeof(error)=='function'){ error(xmlHttp.responseText,xmlHttp.status); } elseif(xmlHttp.status/100==200&&typeof(complete)=='function'){ complete(xmlHttp.responseText,xmlHttp.status); } elseif(typeof(failed)=='function'){ failed(xmlHttp.responseText,xmlHttp.status); } } catch(e){ } } } xmlHttp.setRequestHeader('Content-Type','application/json;charset=utf-8'); xmlHttp.setRequestHeader('SOAPAction',action); xmlHttp.send(data); }
比如请求调用Webservice1中的HelloWorld方法:
webservice('/Webservice1.asmx','HelloWorld','{}',function(msg){alert(msg);});
调用前请记得把Webservice1上面的[System.Web.Script.Services.ScriptService]取消注释,调用后可以看到弹出警告窗口:{"d":"HelloWorld"}。把Content-Type设为text/xml时,警告窗口的内容变就变成了<?xmlversion="1.0"encoding="utf-8"?><stringxmlns="
这时候虽然参数“{}”还是JSON的形式请求却是XML格式,但因为HelloWorld没有参数,所以忽略了内容的格式,能够正常返回值。
如果修改服务端的HelloWorld方法,添加一个string类型的参数somebody。
[WebMethod]
publicstringHelloWorld(stringsomebody){
return"HelloWorld&Hello,"+somebody+"!";
}
将请求端的Content-Type改回application/json,传送参数改为{"somebody":"Krime"},调用后弹出窗口内容变为{d:"HelloWorld&Hello,Krime!"}。
但如果这时再直接把Content-Type改为text/xml,调用后服务器将会报错:System.InvalidOperationException:请求格式无效:text/xml;charset=UTF-8。在System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()在System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()
于是我们把参数格式也修改一下,按照Webservice调试页面的示例,将参数改为:
<?xmlversion="1.0"encoding="utf-8"?>
<soap:Envelopexmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<HelloWorldxmlns="http://tempuri.org/">
<somebody>Krime</somebody>
</HelloWorld>
</soap:Body>
</soap:Envelope>
这样应该就能正常返回XML的结果了吧?结果却出乎意料,服务器仍然报同样的错误。
折腾了很久后,几乎要抓狂了,难道ASP.NET突然不认识XML了?这个时候,再回去仔细看看Webservice调试页面的示例,终于发现了一点问题:
POST/WebServiceTest/Webservice1.asmxHTTP/1.1
Host:localhost
Content-Type:text/xml;charset=utf-8
Content-Length:length
SOAPAction:"http://tempuri.org/HelloWorld"
<?xmlversion="1.0"encoding="utf-8"?>
<soap:Envelopexmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<HelloWorldxmlns="http://tempuri.org/">
<somebody>string</somebody>
</HelloWorld>
</soap:Body>
</soap:Envelope>
上面POST的地址后面并没有像请求JSON数据时一样加上/方法名,而SOAPAction的方法名前面还需要加上命名空间。于是修改XMLHttpRequest的请求头,url和action做相应修改,结果终于正常返回了XML的结果:<?xmlversion="1.0"encoding="utf-8"?><soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><HelloWorldResponsexmlns="http://tempuri.org/"><HelloWorldResult>HelloWorld&Hello,Krime!</HelloWorldResult></HelloWorldResponse></soap:Body></soap:Envelope>
后来继续测试,发现请求内容类型为application/json时,SOAPAction完全可以忽略不加,但是url后面一定要加上/方法名,否则服务器不会返回数据。而请求text/xml时,SOAPAction是必须的且前面要加上命名空间,url后面则不能有/方法名。
最后,经过总结,将代码改成了最终的样子:
functiongetXmlHttp(){
varxmlHttp;
if(window.XMLHttpRequest)
{//codeforIE7+,Firefox,Chrome,Opera,Safari
xmlHttp=newXMLHttpRequest();
}
else
{//codeforIE6,IE5
xmlHttp=newActiveXObject('Microsoft.XMLHTTP');
}
returnxmlHttp;
}
functionwebservice(url,options){
if(typeof(url)=='object'){//将url写在options里的情况
options=url;
url=url.url;
}
if(!url)return;
if(options.dataType.toLowerCase()=='json'){//请求JSON格式的数据时,url后面需要加上“/方法名”
url=url+'/'+options.method;
}
varxmlHttp=getXmlHttp();//获取XMLHttpRequest对象
xmlHttp.open('POST',url,true);//异步请求数据
xmlHttp.onreadystatechange=function(){
if(xmlHttp.readyState==4){
try{
if(xmlHttp.status==200&&typeof(options.success)=='function'){
options.success(xmlHttp.responseText);
}
elseif((xmlHttp.status/100==4||xmlHttp.status/100==5)&&typeof(options.error)=='function'){
options.error(xmlHttp.responseText,xmlHttp.status);
}
elseif(xmlHttp.status/100==200&&typeof(options.complete)=='function'){
options.complete(xmlHttp.responseText,xmlHttp.status);
}
elseif(typeof(options.failed)=='function'){
options.failed(xmlHttp.responseText,xmlHttp.status);
}
}
catch(e){
}
}
}
xmlHttp.setRequestHeader('Content-Type',options.contentType);//设置请求头的ContentType
xmlHttp.setRequestHeader('SOAPAction',options.namespace+options.method);//设置SOAPAction
xmlHttp.send(options.data);//发送参数数据
}
请求JSON数据:
window.onload=function(){
vardata='{"somebody":"Krime"}';
varoptions={
namespace:'http://tempuri.org/',
method:'HelloWorld',
contentType:'application/json;charset=utf-8',
dataType:'json',
data:data,
success:function(msg){
alert(msg);
}
};
webservice('http://localhost:8003/WebServiceTest/Webservice1.asmx',options);
};
请求XML数据:
window.onload=function(){
vardata='<?xmlversion="1.0"encoding="utf-8"?>'
+'<soap:Envelopexmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'
+'<soap:Body>'
+'<HelloWorldxmlns="http://tempuri.org/">'
+'<somebody>Krime</somebody>'
+'</HelloWorld>'
+'</soap:Body>'
+'</soap:Envelope>';
varoptions={
namespace:'http://tempuri.org/',
method:'HelloWorld',
contentType:'text/xml;charset=utf-8',
dataType:'xml',
data:data,
success:function(msg){
alert(msg);
}
};
webservice('http://localhost:8003/WebServiceTest/Webservice1.asmx',options);
};
测试情况正常。
需要注意的一点是,请求JSON数据时,如果返回类型是DataTable是不行的,需要转换成相应数据实体类的List<>再返回。
在解决返回XML问题的过程中,还找到另一种解决方法。具体操作时,是将ContentType设为application/x-www-form-urlencoded,数据体不用JSON也不用XML格式的SOAP包,而是用类似QueryString的“arguement1=XXX&arguement2=XXX”。这个方法是模拟了窗体数据的HTTPPOST格式,将每个控件值编码为名称=值对发送出去。
这种情况下的页面地址后面也需要加上/方法名。
相关文章推荐
- 分享XmlHttpRequest调用Webservice的一点心得
- 分享XmlHttpRequest调用Webservice的一点心得
- 使用 XMLHttpRequest 实现 Ajax 四:调用 Webservice
- xmlHttpRequest调用webservice
- XMLHttpRequest调用webservice出错 (web.config配置)
- HttpWebRequest 调用 WebService 返回 xml
- [转载]通过HttpWebRequest在后台对WebService进行调用
- Javascript+xmlhttp调用Webservice
- 使用ASIHttpRequest调用WebService
- 使用XMLHttprequest对象进行异步调用html页面的示例
- iOS学习之2-使用ASIHttpRequest调用WebService
- 用httpWebRequest调用https开头的php webservice,报“基础连接已经关闭: 未能为SSL/TLS 安全通道建立信任关系”错误的解决方法
- Silverlight用WebClient and HttpWebRequest两种方式来调用WebService
- ajax XMLHttpRequest.readyState: 状态码 0 - (未初始化)还没有调用send()方法 解决了
- xmlhttprequest 跨域调用的方法
- Android--通过Http协议向web服务器发送XML数据和调用webService
- XMLHttpRequest 对象异步调用web服务
- WebService发布与调用问题:expected: {http://schemas.xmlsoap.org/soap/envelope/}Envelope but found: {http://schemas.xmlsoap.org/wsdl/}def
- 使用XmlHttpRequest对象调用Web Services 服务 (源码下载)
- iOS上利用ASIHTTPRequest调用WebService的例子