浏览器同源策略
如果两个URL的域名和端口都相同,则表示它们同源。在非同源的情况下,从一个域上加载的脚本(js),是不允许访问另外一个非同源域中的文档的。
跨域资源共享
跨域资源共享,是浏览器的一种机制,允许应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。header中定义的CORS,定义浏览器与服务器进行交互,以确定是否允许跨域请求的方法。
//表示对所示域名提供跨域权限,多个域名用','隔开,*表示允许所有,
Access-Control-Allow-Origin:www.why.com
//允许请求的类型
Access-Control-Request-Method:GET, POST
//指明实际请求中允许携带的首部字段
Access-Control-Allow-Headers:Content-Type, Authorization, Accept, Range, Origin
//在跨域访问时只能拿到Cache-Control,Content-Language,Content-Type,Expires、Last-Modified等基本相应头,如果要访问其他头,需要额外设置
Access-Control-Expose-Headers:Content-Range
//浏览器必须首先使用OPTIONS方法发起一个预检请求,从而获知服务端是否允许该跨域请求,这里指定了预检请求的结果能够被缓存多久
Access-Control-Max-Age:3600
JSONP资源加载安全
JSONP (json with padding)就是利用script标签的跨域能力实现跨域数据的访问,请求动态生成的js脚本同时带一个callback函数名作为参数。其中callback函数可以调用本地文档的js函数,服务器端动态生成的脚本会产生数据,并在代码中以产生的数据为参数调用callback参数。
是不是听起来有点晕?没关系,记住下面两点就好:
- script脚本可以跨域请求
- 请求的数据通过参数传回script脚本,写入页面
下面看个例子:
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<script type="text/javascript">
function jsonpCallback( result ) {
var divs = document.getElementById('data');
for( var i in result ) {
divs.innerHTML += i + ":" + result[i] + "<br>";
}
}
var JSONP = document.createElement("script");
JSONP.type = "text/javascript";
JSONP.src = "http://localhost:8080?callback=jsonpCallback";
document.getElementsByTagName("head")[0].appendChild(JSONP);
/script>
<div id="data"> </div>
<?php
class Jsonp
{
private $allowOrigin = [
'http://localhost',
'http://localhost:80',
'http://localhost:8080',
];
public function jsonpEncode($url, $callBack, $data )
{
if ( empty($_GET[$callBack]) ){
return false;
}
if ( !$this->check($url) ){
return false;
}
return $_GET[$callBack] . '(' . json_encode($data) . ')';
}
/**
* @param $origin $_SERVER['HTTP_ORIGIN']
*/
private function check($origin)
{
if ( !in_array($origin. $this->allowOrigin) ){
return false;
}
$this->setAccess($origin);
}
private function setAccess($origin)
{
header('Access-Control-Allow-Origin:' . $origin);
header('Access-Control-Allow-Credentials:true');
header('Access-Control-Request-Method:GET, POST');
header('Access-Control-Allow-Headers:Content-Type, Authorization, Accept, Range, Origin');
header('Access-Control-Expose-Headers:Content-Range');
header('Access-Control-Max-Age:3600');
}
}