跨域一

要明白什么是跨域,先要了解什么是同源策略,它的含义是指:

A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同"。

  • 协议相同
  • 域名相同
  • 端口相同

例如我的个人网站:http://www.tuituibang.top
协议是http://,域名是 www.tuituibang.top,端口是80(默认端口可以省略)
http://www.tuituibang.top/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://v2.www.tuituibang.top/other.html:不同源(域名不同)
http://www.tuituibang.top:8080/other.html:不同源(端口不同)
https://www.tuituibang.top/other.html:不同源(协议不同)

为什么要有同源策略,同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。如果是非同源的网站,则受到以下的限制:

  • Cookie、LocalStorage 和 IndexDB 无法读取。
  • DOM 无法获得。
  • AJAX 请求不能发送。
什么是跨域?跨域有几种实现形式
一:降域

例如:
one.tuituibang.com设置:document.domain = 'tuituibang.com'
two.tuituibang.com设置:document.domain = 'tuituibang.com'
one.tuituibang.comtwo.tuituibang.com就可以通过降域来带到跨域传递数据
注:
1.两个网页一级域名相同,只是二级域名不同,才能进行降域
2.这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法,规避同源政策
3.降域这个方法还是避免使用,有一定的安全隐患

二:window.postMessage

如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。
HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。
这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。
举例:
父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法就可以了。

var popup = window.open('http://bbb.com/', 'title');
popup.postMessage('Hello World!', 'http://bbb.com/');

postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。

子窗口向父窗口发送消息的写法类似:

window.opener.postMessage('Nice to see you', 'http://aaa.com/');

父窗口和子窗口都可以通过message事件,监听对方的消息。

window.addEventListener('message', function(e) {
  console.log(e.data);
},false);

message事件的事件对象event,提供以下三个属性。

  • event.source:发送消息的窗口
  • event.origin: 消息发向的网址
  • event.data: 消息内容

下面的例子是,子窗口通过event.source属性引用父窗口,然后发送消息。

window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
   event.source.postMessage('Nice to see you!', '*');
}

event.origin属性可以过滤不是发给本窗口的消息。

window.addEventListener('message', receiveMessage);
function receiveMessage(event) { 
  if (event.origin !== 'http://aaa.com/') return; 
  if (event.data === 'Hello World') { 
      event.source.postMessage('Hello', event.origin); 
  } 
  else { 
      console.log(event.data); 
  }
}
三:JSONP

JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,需要被跨域的网站服务端进行配合
例如:

function addScriptTag(src) { 
        var script = document.createElement('script');
        script.setAttribute("type","text/javascript"); 
        script.src = src; 
        document.body.appendChild(script);
}
window.onload = function () { 
        addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) { 
        console.log('Your public IP address is: ' + data.ip);
};

动态添加<script>标签,向服务器example.com发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSONP是必需的。

后台的代码:

foo({
  "ip": "8.8.8.8"
});

由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。

JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都 可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。

JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

四:CORS

CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。

浏览器将CORS请求分成两类:######

简单请求(simple request)和非简单请求(not-so-simple request)。
简单请求:
(1) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足上面两个条件,就属于非简单请求。

下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin字段。

GET /cors HTTP/1.1
Origin: http://api.bob.com/
Host: api.alice.com
Accept-Language: en-USConnection: 
keep-aliveUser-Agent: Mozilla/5.0...

上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。
如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-开头。
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
(3)Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。

要使用CORS,我们需要了解前端和服务器端的使用方法。
1、 前端
以前我们使用Ajax,代码类似于如下的方式:

var xhr = new XMLHttpRequest();  
xhr.open("GET", "/index.html", true);  
xhr.send();  

这里的“/index.html”是本域的相对路径。
如果我们要使用CORS,相关Ajax代码可能如下所示:

var xhr = new XMLHttpRequest();  
xhr.open("GET", "http://www.tuituibang.top/index.html", true);  
xhr.send();  

请注意:
代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。
提供浏览器回退功能检测和支持,避免浏览器不支持的情况。

function createCORSRequest(method, url) {  
  var xhr = new XMLHttpRequest();  
  if ("withCredentials" in xhr) {  
    // 此时即支持CORS的情况  
    // 检查XMLHttpRequest对象是否有“withCredentials”属性  
    // “withCredentials”仅存在于XMLHTTPRequest2对象里  
    xhr.open(method, url, true);  
   
  } else if (typeof!= "undefined") {  
    // 否则检查是否支持XDomainRequest,IE8和IE9支持  
    // XDomainRequest仅存在于IE中,是IE用于支持CORS请求的方式  
    xhr = new XDomainRequest();  
    xhr.open(method, url);  
   
  } else {  
    // 否则,浏览器不支持CORS  
    xhr = null;    
  }  
  return xhr;  
}  
   
var xhr = createCORSRequest('GET', url);  
if (!xhr) {  
  throw new Error('CORS not supported');  
}  

服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
Apache:Apache需要使用mod_headers模块来激活HTTP头的设置,它默认是激活的。你只需要在Apache配置文件的<Directory>, <Location>, <Files>或<VirtualHost>的配置里加入以下内容即可:

Header set Access-Control-Allow-Origin *  

后台PHP:

Access-Control-Allow-Origin: http://www.tuituibang.top

下面的设置使得只有http://www.tuituibang.top这个域才能跨域访问服务器的API。

目前只涉及到简单请求,非简单请求后续补充

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 题目1.什么是同源策略? 同源策略(Same origin Policy): 浏览器出于安全方面的考虑,只允许与本...
    FLYSASA阅读 1,752评论 0 6
  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    Yaoxue9阅读 1,325评论 0 6
  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    他方l阅读 1,077评论 0 2
  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    HeroXin阅读 855评论 0 4
  • 参考:浏览器的同源策略浏览器同源政策及其规避方法同源政策 什么是同源策略? 同源策略限制了从同一个源加载的文档或脚...
    DHFE阅读 563评论 0 0