用ajax访问一个service, 后端的service是用C++,CppCMS框架,作者给的例子是python写的例子利用JSON-RPC访问的方法,,需要设置Content-Type:application/json, 经测试,python可以正常访问到这个service。
新建立一个本地的html测试后,设置了xhr.setRequestHeader("Content-Type","application/json");
测试的结果是ie8 能够正常设置Content-Type, 能够和后端交互,服务器端返回status200, 获得正确结果。
但是chrome里和 ff里反复设置content-type,都不成功,在浏览器的网络面板里也没看到发出去的请求。用fiddler等工具也没有发现正确的请求头部和正确的应答结果。
在 chrome里只有设置了xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded,application/json; charset=utf-8");才能在网络面板里看到,但是被浏览器给canceled掉了.
而且Content-Type中在把application/json放到了后边也没有请求,从这个可以发现,application/json;必须要设置为第一个参数。
调了很长都未果,后来用firebug的rest插件模拟一个请求,设置content-type:application/json, 参数"{'method':'sum','params':[1,2],'id':1}",得到正确的结果3,考虑到这些发现了是一个跨域的问题,解决了同源策略问题后,得到了正确的结果,Content-Type也正确的设置上了。
注意:IE6不支持JSON-RPC 的这种方式
简单说一下JSON-RPC
JSON-RPC分为1.0 和 2.0
1.0的参数设置 可以参考http://json-rpc.org/wiki/specification
· method - A String containing the nameof the method to be invoked.
· params - An Array of objects to passas arguments to the method.
· id - The request id. This can beof any type. It is used to match the response with the request that it isreplying to.
method:是请求的方法名
params:是一个参数数组
id:是一个唯一的id
一个例子是"{'method':'sum','params':[1,2],'id':1}";
测试代码如下:
var xhr = new XMLHttpRequest();
var params = "{'method':'sum','params':[1,2],'id':1}";
xhr.open("post", “path /rpc”, true);
xhr.setRequestHeader("Content-Type","application/json"); //要再open方法后调用
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
alert("ok")
}
}
}
xhr.send(params);
Web开发由于需要经常进行ajax请求,很多时候涉及到跨域,由于浏览器的同源策略,所以会影响到正确的请求和返回数据。
关于同源策略(Same Origin Policy)
最早源于Netscape Navigator 2.0,在浏览器端是一个重要的安全策略。同源是指,域名相同,应用层协议相同,端口相同,当这些属性完全一致时时才被认为是同源。所以当遇到下面的访问时都要考虑到跨域的问题。
例如果一个页面: http://www.test.com/
父域名是test.com.
子域是
www.test.com
lab.test.com等
一些跨域的情况,当前页面是:
http://www.test.com/1/index.html
如果访问下边的页面
页面 结果 原因
http://www.test.com/2/index.html 成功 同协议 同host
http://www.test.com:82/1/other.html 失败 不同端口80 82
https://www.test.com/1/other.html 失败
http://en.test.com/1/other.html 失败
跨域的一些方案
1 跨子域之间的相互访问
例如父域名都是test.com,子域是www.test.com 和other.test.com,
在www.test.com要通过ajax请求other.test.com页面里的一个文本other.test.com/1.txt.
这样直接请求由于是跨子域是返回不了数据的.
跨子域可以通过把两个页面都要设置domain = test.com
首先要包括子页面的一个iframe文件
<iframe src=”other.test.com/iframe.html” id=“crossIframe” ></iframe>
然后设置domain
document.domain = " test.com";
获得这个iframe的窗口,这里用jquery框架方便调用
contentWindow是获得框架中的窗口,类似于window
var crossIframe = document.getElementById("crossIframe").contentWindow.$;
var url ="other.test.com/1.txt";
crossIframe.get(url,function(data){
alert("成功");
}
);
在other.test.com/iframe.html里要include jquery库文件
document.domain = “test.com”;
这样就可以在test.com的html页面中成功获取1.txt了
2 用注入方式跨域,经常说的jsonp
注入的主要跨域思路是建一个script脚本,append进head或者是body.
有两种方法
第一个种是在<script>标记中
例如当前的地址是www.abc.com. 要访问www.xyz.com/getResult的服务
<script src="www.xyz.com/getResult?name=hiro& &callback=?"></script>
该脚本会向www.xyz.com/getResult发送请求,该服务返回的格式要是javascript可以执行的代码,当script调用成功后,会自动调用callback.
这里需要的就是www.abc.com 里要有一个callback函数,以便刚才的script脚本成功执行后的回调。
function callback(data){
alert(data); //data为script脚本成功调用返回的数据
}
第二种是:
把刚才的url传入即可,动态生成一个script元素,然后插入document或者head
function JSON(url){ // 调用JSONP服务器,url为请求服务器地址
var script =document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src",url);
script.setAttribute("id", url);
document.appendChild(script);
}
或者用jquery框架
var url = "http://www.xyz.com/getResult?name=hiro&callback=?";
$.get(url, {"targetId":targetId}, function(data){
},"json");
1.2版本以上只要上面写一个占位符?就可以,Jquery会把自动会把callback=?转换为注入方式
或者用jquery的$.ajax
$.ajax({
type:"get",
data:{},
url:url,
dataType:"jsonp",
jsonp:"callback",
success:function(data){
}
});
3利用iframe进行两个站点的跨域
刚才所说的是跨子域的iframe方法,如果跨两个域的方法会更麻烦一些,利用iframe + location hash值进行通信。
4用后端语言作为中间层
可以用例如java c#,python等做为中间层取去请求服务,然后再返回本域的数据。