一个域名地址的组成:
浏览器有一个很重要的概念——同源策略(Same-Origin Policy)。所谓同源是指域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况下,不能读写对方的资源。当协议、子域名、主域名、端口号中任意一个不同时,都算做不同域,不同域之间相互请求资源,就算做“跨域”。
跨域解决方法:
1、代理(后台解决);
2、JSONP(针对 GET 方式);
3、XHR2(IE10以下不支持)。
JSONP
Jsonp原理:
首先在客户端注册一个callback, 然后把callback的名字传给服务器。此时,服务器先生成 json 数据。然后以 javascript 语法的方式,生成一个function,function 名字就是传递上来的callback的名字。最后将事先生成的 json 数据直接以参数的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。客户端浏览器解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里。
JSONP实例:百度搜索
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
*{ margin: 0; padding: 0;}
#q{ display: block; width: 300px; height: 30px; border: 1px solid #e1e1e1; margin: 50px auto 0;}
#ul1{ list-style: none; width: 300px; border: 1px solid #EDEDED; margin: -1px auto 0; display: none;}
#ul1 li a{ display: block; height: 30px; line-height: 30px; padding: 0 5px; text-decoration: none; color: #666;}
#ul1 li a:hover{ background: #ededed;}
</style>
<script type="text/javascript">
function jsonpCallback(data){
var oUl=document.getElementById("ul1");
var html='';
if (data.s.length) {
oUl.style.display='block';
for (var i=0; i<data.s.length; i++) {
html+='<li><a target="_blank" href="https://www.baidu.com/s?wd='+ data.s[i] +'">'+ data.s[i] +'</a></li>';
}
oUl.innerHTML=html;
}else{
oUl.style.display='none';
}
}
window.onload=function(){
var oQ=document.getElementById("q");
var oUl=document.getElementById("ul1");
oQ.onkeyup=function(){
if (this.value!='') {
var oScript=document.createElement('script');
oScript.src='https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?json=1&cb=jsonpCallback&wd='+this.value;
document.body.appendChild(oScript);
}else{
oUl.style.display='none';
}
}
document.onclick=function(){
oUl.style.display='none';
}
}
</script>
</head>
<body>
<input id="q" type="text" />
<ul id="ul1">
<!--<li><a target="_blank" href="#">11</a></li>
<li><a target="_blank" href="#">22</a></li>
<li><a target="_blank" href="#">33</a></li>-->
</ul>
</body>
</html>
JSONP并不是所有跨域通信需求的万灵药,它有一些缺陷。
第一,也是最重要的一点,没有关于 JSONP 调用的错误处理。如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。例如,不能从服务器捕捉到 404 错误,也不能取消或重新开始请求。
JSONP 的另一个主要缺陷是被不信任的服务使用时会很危险。因为 JSONP 服务返回打包在函数调用中的 JSON 响应,而函数调用是由浏览器执行的,这使宿主 Web 应用程序更容易受到各类攻击。
JQ应用JSONP的实例:上文中的案例,当把GET方法中请求的url由”http://localhost/ajaxdemo/server.php“改为”http://127.0.0.1/ajaxdemo/server.php“之后,就出现了跨域问题。
解决之后的前端代码:
<script src="http://apps.bdimg.com/libs/jquery/1.11.1/jquery.js"></script>
<script>
$(document).ready(function(){
$('#search').click(function(){
$.ajax({
type:"GET",
url:"http://127.0.0.1/ajaxdemo/server.php?number=" + $('#keyword').val()+"&"+ Math.random(),
dataType:'jsonp',
jsonp:'callback',
success:function(data){
if (data.success) {
$('#searchResult').html(data.msg);
}else{
$('#searchResult').html('出了错误:'+data.msg);
}
},
error:function(jqXHR){
alert("发生错误:" + jqXHR.status);
}
});
})
})
</script>
可以看出前端代码仅修改增加了以下代码字段:
dataType:'jsonp',
jsonp:'callback',
服务端代码修改后为:
<?php
header("Content-Type: application/json;charset=utf-8");
$staff = array
(
array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),
array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),
array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")
);
if ($_SERVER["REQUEST_METHOD"] == "GET") {
search();
} elseif ($_SERVER["REQUEST_METHOD"] == "POST"){
create();
}
function search(){
$jsonp=$_GET["callback"];
if (!isset($_GET["number"]) || empty($_GET["number"])) {
echo $jsonp.'({"success":false,"msg":"参数错误"})';
return;
}
global $staff;
$number = $_GET["number"];
$result = '{"success":false,"msg":"没有找到员工"}';
foreach ($staff as $value) {
if ($value["number"] == $number) {
$result = $jsonp.'({"success":true,"msg":"找到员工:员工编号:' . $value["number"] .
',员工姓名:' . $value["name"] .
',员工性别:' . $value["sex"] .
',员工职位:' . $value["job"] . '"})';
break;
}
}
echo $result;
}
?>
XHR2
HTML5中提供的XMLHttpRequest Level2(即XHR2)已经实现了跨域访问。但ie10以下不支持。
只需要在服务端填上以下响应头:
header("Access-Control-Allow-Origin:*");
/*星号表示所有的域都可以接受,*/
header("Access-Control-Allow-Methods:GET,POST");
总结:代理实现最麻烦,但使用最广泛,任何支持AJAX的浏览器都可以使用这种方式。JSONP相对简单,但只支持GET方式调用。XHR2最简单,但只支持HTML5,如果是移动端开发,可以选择使用XHR2。