背景

曾经负责公司的API,因为使用web service,技术也有点老了,现在都流行JSON了,于是经常有人问到这玩意怎么调用啊 包括各种语言,Java,PHP 这些还好,毕竟常用的有文档。 但是突然有一天,有个客户突然问道我直接在浏览器中能不能调用你们的服务啊。 但是以为只是调用普通的方法,普通方法不含复杂类型是可以直接用GET方法调用的, 即使要POST也是可以借助js完成。于是就回答完全可以呀。 过后发现他要调用的接口是这样的:

http://service.rspread.com/service.asmx?op=createCampaign

即: file

campaignArgs是个对象我们内部定义的一个对象类型。 这玩意可没办法直接在GET参数中传递过来。 经过一番搜索后意识到,其实也不是没办法 不就是SOAP么 也只是XML而已啦 请求也是HTTP的的POST/GET而已

用JS实现调用Web Services

也就是说这东西完全就是当普通的POST请求就可以了

为了简单演示,这里使用jQuery说明,SOAP 1.1 ,格式如下:

var soapMessage =
    '<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>'+
            '<SomeMethod>'+
                '<Arg1>Arg1 Value</Arg1>'+
                '<Arg2>Arg2 Value</Arg2>'+
            '</SomeMethod>'+
        '</soap:Body>'+
    '</soap:Envelope>';

$.ajax({
    url: "http://localhost/someService.svc",
    type: "POST",
    dataType: "xml",
    contentType: "text/xml; charset=\"utf-8\"",
    headers: {
        SOAPAction: "http://localhost/someService/SomeMethod"
    },
    data: soapMessage,
    success: function(soapResponse){
        //DO SOMETHING
    }
});

现在把相应的Web Services接口文档看下把body的内容复制过来上面替换掉请求的URL就可以了,headers内容可选。

上面的是SOAP 1.1版本的。

SOAP 1.2的格式是这样的(仅以这里的接口为例,具体请以自己的为准):

body格式不同,content type也不同。

POST /service.asmx HTTP/1.1
Host: service.rspread.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <createCampaign xmlns="http://service.reasonablespread.com/">
      <loginEmail>string</loginEmail>
      <password>string</password>
      <campaignArgs>
        <campaignName>string</campaignName>
        <fromEmail>string</fromEmail>
        <from>string</from>
        <subject>string</subject>
        <content>string</content>
        <signature>string</signature>
        <schedule>dateTime</schedule>
      </campaignArgs>
      <category>
        <string>string</string>
        <string>string</string>
      </category>
      <interval>int</interval>
    </createCampaign>
  </soap12:Body>
</soap12:Envelope>
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <createCampaignResponse xmlns="http://service.reasonablespread.com/">
      <createCampaignResult>int</createCampaignResult>
    </createCampaignResponse>
  </soap12:Body>
</soap12:Envelope>

事情没那么简单

上面我本地进行测试的时候是没有问题的,因为我负责API这个项目,本地是有部署的即访问localhots是可以访问本地的API,我jQuery也是用的localhost这自然很顺利,但是改成线上的API的链接 后发现并没有返回预期结果!

怎么回事?

在chrome中调试才意识到这样请求是属于异步请求,而且是跨域请求

跨域概念:只要协议、域名、端口有任何一个不同,都被当作是不同的域。

现代浏览器通常会禁止ajax跨域请求(为了安全)。

所以我写出测试js是在localhost发出的,目标url是线上的自然就被拦截了。

解决方案

API服务器端允许跨域请求,

服务器端直接设置header内容 Access-Control-Allow-Origin:* 或者 Access-Control-Allow-Origin:http://api.HostExample.com

(用户旁白:API不是我的, 没法控制。。)

要么想办法解除这种跨域请求的限制

参考这里或者下面

那目前可以实现POST的方法是

1、建立一个iframe,iframe内的JS创建一个form表单,并可以将接收到的参数放入表单中POST提交。 2、将iframe页面插入到页面中。 3、针对现代浏览器,将数据通过postMessage()方法传入iframe中。针对不支持此方法的浏览器,通过URL HASH的方法将参数传入iframe中。 (由于URL有长度限制,所以不能传播大数据)

注:上述两点内容未经测试,可行性不保证(ε=ε=ε=┏(゜ロ゜;)┛)

或者有其他,请补充