背景
曾经负责公司的API,因为使用web service,技术也有点老了,现在都流行JSON了,于是经常有人问到这玩意怎么调用啊 包括各种语言,Java,PHP 这些还好,毕竟常用的有文档。 但是突然有一天,有个客户突然问道我直接在浏览器中能不能调用你们的服务啊。 但是以为只是调用普通的方法,普通方法不含复杂类型是可以直接用GET方法调用的, 即使要POST也是可以借助js完成。于是就回答完全可以呀。 过后发现他要调用的接口是这样的:
http://service.rspread.com/service.asmx?op=createCampaign
即:
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有长度限制,所以不能传播大数据)
注:上述两点内容未经测试,可行性不保证(ε=ε=ε=┏(゜ロ゜;)┛)
或者有其他,请补充