• XmlHttpRequest调用Webservice的一点心得


    因为项目需要,以后前端、手机客户端调用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出去。

    代码如下:

        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格式,将每个控件值编码为名称=值对发送出去。

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

  • 相关阅读:
    12.10
    4.06Android使用EditText小技巧汇总
    4.05
    4.04Android学习
    4.03Android学习
    4.02Android学习
    4.01Android学习
    3.31构建之法读后感3
    3.30Android学习
    3.29Android学习
  • 原文地址:https://www.cnblogs.com/dashublog/p/2597872.html
Copyright © 2020-2023  润新知