分享XmlHttpRequest调用Webservice的一点心得


Posted in Javascript onJuly 20, 2012

首先,因为JSON对于JS的便利性,考虑通过JSON来请求和返回数据。在JS中实例化一个xmlHttpRequest对象,然后根据网上的说明POST的地址为:asmx页面地址/Web方法名。在RequestHeader中设置Content-Type为application/json; charset=utf-8,SOAPAction设为Web方法名。Web方法的参数用JSON格式send出去。
代码如下:

function getXmlHttp() { 
var xmlHttp; 
if (window.XMLHttpRequest) 
{ // code for IE7+, Firefox, Chrome, Opera, Safari 
xmlHttp = new XMLHttpRequest(); 
} 
else 
{ // code for IE6, IE5 
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); 
} 
return xmlHttp; 
} 
function webservice(url, action, data, success, error, complete, failed) { 
var xmlHttp = 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); 
} 
else if ((xmlHttp.status / 100 == 4 || xmlHttp.status / 100 == 5) && typeof (error) == 'function') { 
error(xmlHttp.responseText, xmlHttp.status); 
} 
else if (xmlHttp.status / 100 == 200 && typeof (complete) == 'function') { 
complete(xmlHttp.responseText, xmlHttp.status); 
} 
else if (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": "Hello World"}。把Content-Type设为text/xml时,警告窗口的内容变就变成了<?xml version="1.0" encoding="utf-8"?> <string xmlns="http://tempuri.org/">Hello World</string>。
这时候虽然参数“{}”还是JSON的形式请求却是XML格式,但因为Hello World没有参数,所以忽略了内容的格式,能够正常返回值。
如果修改服务端的HelloWorld方法,添加一个string类型的参数somebody。
[WebMethod] 
public string HelloWorld(string somebody) { 
return "Hello World&Hello, " + somebody + "!"; 
}

将请求端的Content-Type改回application/json,传送参数改为{"somebody": "Krime"},调用后弹出窗口内容变为{d: "Hello World&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调试页面的示例,将参数改为:
<?xml version="1.0" encoding="utf-8"?> 
<soap:Envelope xmlns: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> 
<HelloWorld xmlns="http://tempuri.org/"> 
<somebody>Krime</somebody> 
</HelloWorld> 
</soap:Body> 
</soap:Envelope>

这样应该就能正常返回XML的结果了吧?结果却出乎意料,服务器仍然报同样的错误。
折腾了很久后,几乎要抓狂了,难道ASP.NET突然不认识XML了?这个时候,再回去仔细看看Webservice调试页面的示例,终于发现了一点问题:
POST /WebServiceTest/Webservice1.asmx HTTP/1.1 
Host: localhost 
Content-Type: text/xml; charset=utf-8 
Content-Length: length 
SOAPAction: "http://tempuri.org/HelloWorld" 
<?xml version="1.0" encoding="utf-8"?> 
<soap:Envelope xmlns: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> 
<HelloWorld xmlns="http://tempuri.org/"> 
<somebody>string</somebody> 
</HelloWorld> 
</soap:Body> 
</soap:Envelope>

上面POST的地址后面并没有像请求JSON数据时一样加上/方法名,而SOAPAction的方法名前面还需要加上命名空间。于是修改XMLHttpRequest的请求头,url和action做相应修改,结果终于正常返回了XML的结果:<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns: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><HelloWorldResponse xmlns="http://tempuri.org/"><HelloWorldResult>Hello World&Hello, Krime!</HelloWorldResult></HelloWorldResponse></soap:Body></soap:Envelope>
后来继续测试,发现请求内容类型为application/json时,SOAPAction完全可以忽略不加,但是url后面一定要加上/方法名,否则服务器不会返回数据。而请求text/xml时,SOAPAction是必须的且前面要加上命名空间,url后面则不能有/方法名。
最后,经过总结,将代码改成了最终的样子:
function getXmlHttp() { 
var xmlHttp; 
if (window.XMLHttpRequest) 
{ // code for IE7+, Firefox, Chrome, Opera, Safari 
xmlHttp = new XMLHttpRequest(); 
} 
else 
{ // code for IE6, IE5 
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); 
} 
return xmlHttp; 
} 
function webservice(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; 
} 
var xmlHttp = 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); 
} 
else if ((xmlHttp.status / 100 == 4 || xmlHttp.status / 100 == 5) && typeof (options.error) == 'function') { 
options.error(xmlHttp.responseText, xmlHttp.status); 
} 
else if (xmlHttp.status / 100 == 200 && typeof (options.complete) == 'function') { 
options.complete(xmlHttp.responseText, xmlHttp.status); 
} 
else if (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 () { 
var data = '{"somebody": "Krime"}'; 
var options = { 
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 () { 
var data = '<?xml version="1.0" encoding="utf-8"?>' 
+ '<soap:Envelope xmlns: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>' 
+ '<HelloWorld xmlns="http://tempuri.org/">' 
+ '<somebody>Krime</somebody>' 
+ '</HelloWorld>' 
+ '</soap:Body>' 
+ '</soap:Envelope>'; 
var options = { 
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”。这个方法是模拟了窗体数据的HTTP POST格式,将每个控件值编码为名称=值对发送出去。

这种情况下的页面地址后面也需要加上/方法名。

Javascript 相关文章推荐
jQuery 动画弹出窗体支持多种展现方式
Apr 29 Javascript
jQuery JSON实现无刷新三级联动实例探讨
May 28 Javascript
js控制web打印(局部打印)方法整理
May 29 Javascript
JS实现很酷的EMAIL地址添加功能实例
Feb 28 Javascript
简介JavaScript中用于处理正切的Math.tan()方法
Jun 15 Javascript
Jquery表单验证失败后不提交的解决方法
Oct 18 Javascript
js实现图片切换(动画版)
Dec 25 Javascript
在vue中使用echarts图表实例代码详解
Oct 22 Javascript
Vue 组件修改根实例的数据的方法
Apr 02 Javascript
微信小程序开发技巧汇总
Jul 15 Javascript
Vue实现商品飞入购物车效果(电商项目)
Nov 26 Javascript
关于引入vue.js 文件的知识点总结
Jan 28 Javascript
基于jquery的可多选的下拉列表框
Jul 20 #Javascript
基于jquery的DIV随滚动条滚动而滚动的代码
Jul 20 #Javascript
最佳6款用于移动网站开发的jQuery 图片滑块插件小结
Jul 20 #Javascript
基于jquery的图片轮播 tab切换组件
Jul 19 #Javascript
JavaScript面向对象知识串结(读JavaScript高级程序设计(第三版))
Jul 17 #Javascript
JavaScript面向对象(极简主义法minimalist approach)
Jul 17 #Javascript
基于jQuery的获取标签名的代码
Jul 16 #Javascript
You might like
PHP生成静态页
2006/11/25 PHP
从一个不错的留言本弄的mysql数据库操作类
2007/09/02 PHP
windows下升级PHP到5.3.3的过程及注意事项
2010/10/12 PHP
php获取当月最后一天函数分享
2015/02/02 PHP
使用php实现从身份证中提取生日
2016/05/09 PHP
PHP后端银联支付及退款实例代码
2017/06/23 PHP
php和nginx交互实例讲解
2019/09/24 PHP
javascript中window.event事件用法详解
2012/12/11 Javascript
用js替换除数字与逗号以外的所有字符的代码
2014/06/07 Javascript
DOM操作一些常用的属性汇总
2015/03/13 Javascript
关于安卓手机微信浏览器中使用XMLHttpRequest 2上传图片显示字节数为0的解决办法
2016/05/17 Javascript
JavaScript实现自定义媒体播放器方法介绍
2017/01/03 Javascript
js下载文件并修改文件名
2017/05/08 Javascript
67 个节约开发时间的前端开发者的工具、库和资源
2017/09/12 Javascript
本地搭建微信小程序服务器的实现方法
2017/10/27 Javascript
vue2实现数据请求显示loading图
2017/11/28 Javascript
小程序实现带年月选取效果的日历
2018/06/27 Javascript
vue实现自定义多选与单选的答题功能
2018/07/05 Javascript
前端axios下载excel文件(二进制)的处理方法
2018/07/31 Javascript
echarts实现地图定时切换散点与多图表级联联动详解
2018/08/07 Javascript
Vue.js更改调试地址端口号的实例
2018/09/19 Javascript
微信小程序 获取手机号 JavaScript解密示例代码详解
2020/05/14 Javascript
vue仿携程轮播图效果(滑动轮播,下方高度自适应)
2021/02/11 Vue.js
python实现调用其他python脚本的方法
2014/10/05 Python
浅析Python 中整型对象存储的位置
2016/05/16 Python
Python3.5基础之变量、数据结构、条件和循环语句、break与continue语句实例详解
2019/04/26 Python
PyQt5的PyQtGraph实践系列3之实时数据更新绘制图形
2019/05/13 Python
解决python xx.py文件点击完之后一闪而过的问题
2019/06/24 Python
Python运行提示缺少模块问题解决方案
2020/04/02 Python
Python进行特征提取的示例代码
2020/10/15 Python
css3 position fixed固定居中问题解决方案
2014/08/19 HTML / CSS
中学劳技课教师的自我评价
2014/02/05 职场文书
厕所文明标语
2014/06/11 职场文书
2015毕业实习推荐信
2015/03/23 职场文书
朋友圈早安励志语录!
2019/07/08 职场文书
css弧边选项卡的项目实践
2023/05/07 HTML / CSS