资讯专栏INFORMATION COLUMN

前端跨域及解决方案

wayneli / 1794人阅读

摘要:但是如果是一级域名相同,二级及以上域名不同的网页可以通过设置来共享。设置有两种方式前端脚本中设置服务器接口设置时指定所属的域名为一级域名。服务器检查过预检请求头之后,确认允许跨域请求,就可以做出回应。

一、跨域问题产生的原因

根本原因是由于浏览器的“同源政策”。

1.1.同源政策

同源政策由网景公司(Netscape)1995年引入浏览器。目前所有浏览器都实行这个政策。
所谓同源是指“三个相同”:

协议相同

域名相同

端口相同

1.2.限制范围

目前,如果非同源,共有三种行为收到限制。

Cookie、LocalStorage 和 IndexDB 无法读取。

DOM无法获取

AJAX请求不能发送

二、跨域问题处理
2.1 Cookie共享

Cookie是服务器写入浏览器的信息,只有同源的网页才能共享。但是如果是一级域名相同,二级(及以上)域名不同的网页可以通过设置document.domain来共享cookie。

比如,w1.example.com 和 w2.example.com是不同源的,w1.example.com/index.html (A网页) 和 w2.example.com/index.html (B网页)只要设置相同的document.domain就可以共享Cookie。

设置domain有两种方式:1.前端js脚本中设置 2.服务器接口设置cookie时指定Cookie所属的域名为一级域名。

2.1.1 js设置domain

在A网页设置

document.domain = “example.com”;
document.cookie = “userName = aaa”;

这样在B网页就可以读到这个Cookie

var cookie = document.cookie; // userName = aaa;
2.1.2 服务器设置domain
Set-Cookie: userName = aaa ; domain = .example.com ; path = /
2.2 iframe父子窗口共享DOM

如果两个网页不同源,就无法拿到对方的DOM。典型例子是iframe和window.open方法打开的窗口,它们与父窗口无法通信。
如果两个窗口只是二级域名不同,一级域名相同的话,那么设置document.domain属性,就可以规避同源政策。拿到DOM。对于完全不同源的网站,目前有三种方法可以解决跨域窗口通信问题:

片段标识符

window.name

跨文档通信API

2.2.1 片段标识符

片段标识符指的是URL的#后面的部分,如http://example.com/index.html...。如果只是改变片段标识符部分,页面不会刷新。
父窗口可以把信息写入子窗口的片段标识符中,

var src = originURL +  ‘#’ + data;
document.getElementById(‘#iframe’).src = src;

子窗口通过监听hashchange事件得到通知

window.onhashchange = checkMessage;
function checkMessage(){
    var message = window.location.hash;
    //...
}

同样子窗口也可以修改父窗口的片段标识符。

parent.location.href = target + ‘#" + hash;
2.2.2 window.name

浏览器窗口有window.name属性。这个属性最大的特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页就可以读取它。

2.2.3 window.postMessage

postMessage是HTML5引入的一个全新的API:跨文档通信API提供的一个全局方法,允许跨窗口通信,不论是否同源。

父窗口发送message

var popup = window.open(‘http://aaa.com’,"title");
popup.postMessage(‘Hello World’, ‘http://aaa.com");

子窗口监听message事件

window.addeventlistener(‘message’,function( e ){
    console.log( e.data );
});

message事件的event对象提供三个属性

event.source 发送消息的窗口

event.origin 消息发向的网址

event.data 消息内容

2.3 LocalStorage共享

用window.postMessage可解决。

2.4 跨域异步请求(AJAX)

同源政策规定,AJAX只能发给同源的网址,否则会报错。除了用服务器代理的方法(nginx反向代理等),有以下方法可以解决。

2.4.1 JSONP

原理是利用script标签的src属性,接受JSON数据。关键在于规定一个callback方法名,在url中以参数形式传给服务器,由服务器将数据以参数形式注入callback中,供js脚本使用。
缺点是只能发送get请求,优点是支持老式浏览器。

2.4.2 CORS

CORS即跨源资源分享,是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP,CORS允许任何类型的请求。
目前除了IE之外的所有浏览器都支持CORS,IE不能低于IE10版本。
浏览器将CORS请求分为两类,简单请求和非简单请求。

2.4.2.1 简单请求

简单请求条件:

1. 请求方法 GET、POST、HEAD;
2. http头信息不超过 Accept 、Accept-Language 、Content-Language、Last-Event-ID;
3. content-type只限于三个值: application/x-www-form-urlencoded、multipart/form-data、text/plain 

对于简单请求,浏览器的处理是直接发出CORS请求,也就是在头信息中增加一个字段Origin,该字段说明本次请求是来自哪个源(协议+域名+端口)。服务器根据这个值,判断是否同意此次请求。

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

如果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

Access-Control-Allow-Origin:该字段必须,它的值要么是请求是Origin的值,要么是一个*,表示接受任意域名的请求。

Access-Control-Allow-Credentials:该字段可选。值是一个布尔值,表示是否允许发送Cookie,默认为true,表示可以发送。

Access-Control-Expose-Headers:该字段可选。CORS请求是XHR对象的getResponseHeader( ) 方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expire、Last-Modified、Pragma。如果想要拿到其他字段,就要在Access-Control-Expose-Headers中指定。

注意,如果要将Cookie发送到服务器,除了服务器要设置Access-Control-Allow-Credentials字段以外,浏览器在发送AJAX请求是也要保证xhr.withCredentials属性为true,否则浏览器既不会向服务器发送cookie,服务器设置cookie的操作也不会成功。但是默认情况下,该属性是为true的。
另外需要注意的是,如果要操作Cookie,Access-Control-Allow-Origin就不能设置为*,必须明确是哪个网址过来的请求。

对于非简单请求:
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP请求,成为“预检”请求。
浏览器先询问服务器,当前网页所在域名是否在服务器的许可名单中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则报错。
预检请求的方法是OPTIONS,头信息中的关键字是Origin,标识请求来自哪个源。另外还包含两个特殊字段:

Access-Control-Request-Method:该字段是必须的,用于流出浏览器的CORS请求会用到那些HTTP方法。

Access-Control-Request-Headers:该字段用来指定CORS会额外发出的头信息字段。

OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

服务器检查过预检请求头之后,确认允许跨域请求,就可以做出回应。
响应头部信息的关键字段是Access-Control-Allow-Origin,为*或者一个完整域名,表示允许的请求来源。
如果服务器否定了“预检”请求,会返回一个正常的HTTP回应,不包含任何CORS相关的字段。这是浏览器会认定,服务器不同意预检请求,因此会触发一个错误,呗XHR对象的onerror函数捕获。并在控制台打印。
成功的话还有几个与CORS相关的响应头字段:

Access-Control-Allow-Methods:必须。表示服务器支持的跨域请求方法。注意会返回所有支持的方法,以此避免多次预检请求。

Access-Control-Allow-Headers:如果请求头包含该字段,则服务器响应也是必须的。

Access-Control-Allow-Credentials:是否支持cookie传输

Access-Control-Max-Age:可选。用来指定本次预检请求的有效期,单位为秒。在此期间不用发出另一条预检请求。

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

一旦服务器通过了预检请求,以后每次浏览器正常的CORS请求,就和简单请求一样,会有一个Origin字段,服务器回应也会有一个Access-Control-Allow-origin头信息字段。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90154.html

相关文章

  • 理解域及常用解决方案

    摘要:跨域的产生不用多讲,作为一名前端开发人员,相信大家都知道跨域是因为浏览器的同源策略所导致的。浏览器引入同源策略主要是为了防止,攻击。其指明了实际请求所允许使用的方法。 跨域,相信大家无论是在工作中还是在面试中经常遇到这个问题,常常在网上看到别人所整理的一些方法,看似知道是怎么回事,但如果没有动手实践过,总觉得自己没有真正的掌握,在这里,通过自己认真思考整理一些常用的方法。 跨域的产生 ...

    paney129 评论0 收藏0
  • 理解域及常用解决方案

    摘要:跨域的产生不用多讲,作为一名前端开发人员,相信大家都知道跨域是因为浏览器的同源策略所导致的。浏览器引入同源策略主要是为了防止,攻击。其指明了实际请求所允许使用的方法。 跨域,相信大家无论是在工作中还是在面试中经常遇到这个问题,常常在网上看到别人所整理的一些方法,看似知道是怎么回事,但如果没有动手实践过,总觉得自己没有真正的掌握,在这里,通过自己认真思考整理一些常用的方法。 跨域的产生 ...

    only_do 评论0 收藏0
  • 理解域及常用解决方案

    摘要:跨域的产生不用多讲,作为一名前端开发人员,相信大家都知道跨域是因为浏览器的同源策略所导致的。浏览器引入同源策略主要是为了防止,攻击。其指明了实际请求所允许使用的方法。 跨域,相信大家无论是在工作中还是在面试中经常遇到这个问题,常常在网上看到别人所整理的一些方法,看似知道是怎么回事,但如果没有动手实践过,总觉得自己没有真正的掌握,在这里,通过自己认真思考整理一些常用的方法。 跨域的产生 ...

    wemallshop 评论0 收藏0
  • 关于javascript域及JSONP的原理与应用

    摘要:因为同源策略的限制,我们不能在与外部服务器进行通信的时候使用。这个是跨域服务器取数据的接口,参数为回调函数的名字,返回的格式为原理首先在客户端注册一个然后把的名字传给服务器。 一、同源策略 同源策略,它是由Netscape提出的一个著名的安全策略,现在所有的可支持javascript的浏览器都会使用这个策略。 为什么需要同源策略,这里举个例子: 假设现在没有同源策略,会发生什么事...

    CoderBear 评论0 收藏0
  • jsonp跨域获取数据实现百度搜索

    摘要:同源策略做了很严格的限制,但是在实际的场景中,又确实有很多地方需要突破同源策略的限制,也就是我们常说的跨域。使用跨域由于同源策略,一般来说位于的网页无法与不是的服务器沟通,而的元素是一个例外。 本菜鸡最近在写某个页面请求数据时,报了如下的错误。 Failed to load https://...:No Access-Control-Allow-Origin header is pre...

    Tikitoo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<