- 为什么会产生跨域?
跨域是因为浏览器的安全策略:同源策略。服务器是没有做限制的
请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同
如下图
- jsonp方式
原理:有三个标签是不限制同源的分别是<script type="text/javascript" src=""资源地址></script>、type="text/css" rel="stylesheet" href="资源地址"、<img src="资源地址" alt=""/> 。当链接的资源到达浏览器时,浏览器会根据他们的类型来采取不同的处理方式,比如,如果是css文件,则会进行对页面 repaint,如果是img 则会将图片渲染出来,如果是script 脚本,则会进行执行。jsonp方式就是利用了资源到达浏览器会被执行的特性,来达到跨域的目的的。
请看下边的例子
下面是原生js
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="jsonp">
<meta name="description" content="jsonp">
<title>jsonp</title>
</head>
<body>
<script type="text/javascript" src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
var url = "http://shangcheng.com/test";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
function callbackFun(data)
{
console.log(data.age);
console.log(data.name);
}
</script>
</body>
</html>
服务端(以php为例)
header('Content-type:application/json'); //注意一定要设置数据类型为json 不然js解析失败
$json = ['age'=>100,'name'=>'yuanfang'];
return 'callbackFun'.'('.json_encode($json).')'; //这里的callbackFun要与前端回调执行函数一致
因为我用的是laravel框架所以附上laravel demo
$json = ['age'=>100,'name'=>'yuanfang'];
$data = 'callbackFun'.'('.json_encode($json).')';
return response($data,200)->header('Content-type','application/json');
下面是以jq为例演示
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="jsonp">
<meta name="description" content="jsonp">
<title>ajax</title>
<style type="text/css">
*{margin:0;padding:0;}
div{width:600px;height:100px;margin:20px auto;}
</style>
</head>
<body>
<div>
<a href="javascript:;">ajax测试</a>
</div>
<script type="text/javascript" src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
function callbackFun(data)
{
console.log(111);
console.log(data.name);
data.age = 10000000;
alert(0000);
}
$(function(){
$("a").on("click", function(){
$.ajax({
type:"post",
url:"http://shangcheng.com/test",
dataType:'jsonp',
jsonp:'mycallback',
jsonpCallback:'callbackFun',
success:function(data) {
console.log(2222);
console.log(data.age);
}
});
})
});
</script>
</body>
</html>
图片上可以看到ajax回调函数callbackFun和success都被执行了,并且是先执行callbackFun,下边看另外一个例子
可以看到当我们在callbackFun中对返回值做了修改的话success中值会显示变化后的值,并且执行到alert的时候如果我们不点确定,后边success并不会执行,这说明ajax回调是同步执行的。
另外说点其他的,因为jsonp跨域是依赖于<script>所以它一定是get方式,尽管上边jqz中type写的是post但是jq底层会忽略前置设置为get
- cors方式
nginx设置方法,假如你整个项目都需要跨域那么这种方式是比较适合的,在server中设置
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' ;
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Allow-Credentials' 'true' //这个是设置是否接受cookie
laravel设置方法,可以写一个路由中间件来做验证
<?php
namespace App\Http\Middleware;
use Closure;
class CrossHttp
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
//$response->header('Access-Control-Allow-Origin', '*');
//$response->header('Access-Control-Allow-Headers', 'Origin, Content-Type, Cookie, Accept');
//$response->header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, OPTIONS');
// $response->header('Access-Control-Allow-Credentials', 'true');
return $response;
}
}
并且在kernel中注册这个中间件即可
总结jsonp和cors两种优缺点
1)jsonp只可以是get方式,cors可以使get也可以是post
2)cors兼容性不是特别好,低版本的IE不支持