分享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 相关文章推荐
关于B/S判断浏览器断开的问题讨论
Oct 29 Javascript
原生js实现改变随意改变div属性style的名称和值的结果
Sep 26 Javascript
javascript中为某个元素指定事件的三种方式
Aug 07 Javascript
javascript的tab切换原理与效果实现方法
Jan 10 Javascript
使用RequireJS库加载JavaScript模块的实例教程
Jun 06 Javascript
jquery+ajax实现直接提交表单实例分析
Jun 17 Javascript
JS代码实现百度地图 画圆 删除标注
Oct 12 Javascript
vue新vue-cli3环境配置和模拟json数据的实例
Sep 19 Javascript
用node开发并发布一个cli工具的方法步骤
Jan 03 Javascript
30分钟精通React今年最劲爆的新特性——React Hooks
Mar 11 Javascript
webpack4实现不同的导出类型
Apr 09 Javascript
es6数组之扩展运算符操作实例分析
Apr 25 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 无限分类三种方式 非函数的递归调用!
2011/08/26 PHP
一个简洁实用的PHP缓存类完整实例
2014/07/26 PHP
PHP目录与文件操作技巧总结(创建,删除,遍历,读写,修改等)
2016/09/11 PHP
php利用gd库为图片添加水印
2016/11/09 PHP
PHP实现微信提现功能
2018/09/30 PHP
PHP设计模式入门之迭代器模式原理与实现方法分析
2020/04/26 PHP
Javascript 面向对象特性
2009/12/28 Javascript
javascript实现的在当前窗口中漂浮框的代码
2010/03/15 Javascript
js 中的switch表达式使用示例
2020/06/03 Javascript
快速解决jQuery与其他库冲突的方法介绍
2014/01/02 Javascript
深入浅出理解javaScript原型链
2015/05/09 Javascript
js实现超简单的展开、折叠目录代码
2015/08/28 Javascript
JavaScript实现多种排序算法
2016/02/24 Javascript
JavaScript常用函数工具集:lao-utils
2016/03/01 Javascript
JS实现的手机端精简幻灯片效果
2016/09/05 Javascript
vue router2.0二级路由的简单使用
2017/07/05 Javascript
jQuery实现判断滚动条滚动到document底部的方法分析
2019/08/27 jQuery
详解Python中的循环语句的用法
2015/04/09 Python
python3.6+opencv3.4实现鼠标交互查看图片像素
2018/02/26 Python
Django实现表单验证
2018/09/08 Python
对numpy中的where方法嵌套使用详解
2018/10/31 Python
pytorch ImageFolder的覆写实例
2020/02/20 Python
基于python实现判断字符串是否数字算法
2020/07/10 Python
Python unittest如何生成HTMLTestRunner模块
2020/09/08 Python
详解Selenium 元素定位和WebDriver常用方法
2020/12/04 Python
python正则表达式re.match()匹配多个字符方法的实现
2021/01/27 Python
html5应用缓存_动力节点Java学院整理
2017/07/13 HTML / CSS
意大利网上药房:Farmacia 33
2020/01/27 全球购物
出口公司经理求职简历中的自我评价
2013/10/13 职场文书
协议书格式
2014/04/23 职场文书
小学毕业典礼演讲稿
2014/09/09 职场文书
行政助理岗位职责
2015/02/10 职场文书
PHP中strval()函数实例用法
2021/06/07 PHP
AJAX实现指定部分页面刷新效果
2021/10/16 Javascript
python字符串的一些常见实用操作
2022/04/06 Python
默认网关不可用修复后过一会又不好使了解决方法
2022/04/08 数码科技