同源策略
- 域=协议名+主机名+端口号,只有这三部分相同才能称为是相同的域访问。
- 多个页面的协议, 域名, 端口完全相同, 则认为他们遵循了”同源策略”
http://www.baidu.com:80和ftp://www.baidu.com:80 不同域,协议不一样
http://www.baidu.com:80和http://www.xiaomi.com:80 不同域,主机名不一样
http://www.baidu.com:80和http://www.baidu.com:8080 不同域,端口号不一样
http://www.baidu.com:80/a.html和http://www.baidu.com:80/b.js 同域
- 同源策略是一种安全机制
- 浏览器禁止通过脚本发起跨域请求, 如
XMLHttpRequest
,但是允许通知 html 标签属性跨域
跨域解决方法
1.CORS
CORS : 跨源资源共享 Cross-Origin Resource Sharing(CORS) 是一个新的 W3C 标准,它新增的一组HTTP首部字段,允许服务端其声明哪些源站有权限访问哪些资源。换言之,它允许浏览器向声明了 CORS 的跨域服务器,发出 XMLHttpReuest 请求,从而克服 Ajax 只能同源使用的限制。
另外,规范也要求对于非简单请求,浏览器必须首先使用 OPTION 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求,在服务器确定允许后,才发起实际的HTTP请求。
当前域名是
http://php11.cn
,跨域请求域名是http://demo.net
用AJAX,GET请求;
CORS.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跨域请求-CORS</title>
</head>
<body>
<button>跨域请求-CORS</button>
<h2></h2>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click',function () {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
document.querySelector('h2').innerHTML = xhr.responseText;
}
};
xhr.open('GET','http://demo.net/jsonp_demo/CORS.php',true);
xhr.send(null);
},false);
</script>
</body>
</html>
CORS.php
<?php
/**
* Access-Control-Allow-Origin - 限定请求脚本的域名
*/
header('Access-Control-Allow-Origin:http://php11.cn');
echo '跨域请求成功';
2.JSONP
常用的处理方式是JSONP。ajax请求不同域会出现跨域请求,无访问权限,但平时在HTML页面写的<script>、<link>这些标签的src属性是不受跨域请求限制的,于是,JSONP的策略就是服务器端可以动态生成JSON文件,把客户端需要的数据放到这个文件中,让客户端通过<script>标签的src属性来请求这个文件
1.使用JSONP时,可以在页面中声明有这样的一个函数
handle()
,它将作为 JSONP 的回调函数处理作为函数参数传入的数据function handle(jsonData) {
var data = jsonData;
console.log(data);
// 将接口返回的数据渲染到页面中
var ul = document.createElement('ul');
ul.innerHTML += "<li>" + data.name + "</li>";
ul.innerHTML += "<li>邮箱: " + data.email + "</li>";
document.body.appendChild(ul);
}
- 2.然后在url上传参
script.src = "http://demo.net/jsonp_demo/JSONP.php?jsonp=handle&id=1";
- 3.服务端在返回数据的时候,就会返回一端 Javascript 代码,在 Javascript代码中调用了回调函数,并且需要返回的数据作为回调函数的参数
handle({name: "admin", email: "admin@qq.com"})
4.最后页面成功加载了刚才指定路径的资源后,将会执行该 Javascript 代码,
handle()
函数将执行,这时一次跨域请求完成。JSON.HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跨域请求-JSONP</title>
</head>
<body>
<button>跨域请求-JSONP</button>
<script>
//1.准备好回调函数
function handle(jsonData) {
console.log(jsonData)
// var data = JSON.parse(jsonData);
var data = jsonData;
console.log(data);
// 将接口返回的数据渲染到页面中
var ul = document.createElement('ul');
ul.innerHTML += "<li>" + data.name + "</li>";
ul.innerHTML += "<li>邮箱: " + data.email + "</li>";
document.body.appendChild(ul);
}
//2.点击一个按钮发起一个基于JSONP的跨域请求
var btn = document.querySelector('button');
btn.addEventListener(
"click",function () {
var script = document.createElement("script");
script.src = "http://demo.net/jsonp_demo/JSONP.php?jsonp=handle&id=1";
document.head.appendChild(script);
},
false
)
</script>
</body>
</html>
CORS.php
<?php
header('content-type:text/html;charset:utf-8');
$callback = $_GET['jsonp'];
$id = $_GET['id'];
$users = [
['name'=>'admin','email'=>'admin@qq.com'],
['name'=>'html','email'=>'html@qq.com'],
['name'=>'html','email'=>'html@qq.com'],
];
if (array_key_exists(($id-1),$users)) {
$user = $users[$id-1];
}
echo $callback . '(' . json_encode($user) . ')';
总结
1 . JSONP 的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行。
JSONP 的缺点是:它只支持 GET 请求,而不支持 POST 请求等其他类型的 HTTP 请求