前天面试被问到了跨域的问题,自我感觉回答的并不理想,下面我就分享一下整理后的总结分享给大家

一、为什么要跨域

  安全限制

  JavaScript或Cookie只能访问同域下的内容——同源策略

  同源策略

  下表相对于: http://h5.jd.com/dir/ajax.js

  

  注意

  • 协议和端口造成的跨域问题,非前端解决范畴
  • 所谓域,是通过“url首部”来识别,而非判断域与ip的对应关系

  (“URL的首部”指window.location.protocol +window.location.host)

二、跨域方案

1. jsonp

  原理

  HTML里面所有带src属性的标签都可以跨域,如iframe,img,script等。

  所以可以把需要跨域的请求改成用script脚本加载即可,服务器返回执行字符串,但是这个字符串是在window全局作用域下执行的,你需要把他返回到你的代码的作用域内,这里就需要临时创建一个全局的回调函数,并把到传到后台,最后再整合实际要请求的数组,返回给前端,让浏览器直接调用,用回调的形式回到你的原代码流程中。

  • 首先,利用 script 标签的 src 属性实现跨域
  • 通过将前端方法作为参数传递到服务器端,然后由服务器注入参数之后再返回,实现服务器端向客户端通信
  • 由于使用script 标签的src 属性,因此只支持 get 方法

  一个简单的jsonp实现,其实就是拼接url,然后将动态添加一个script元素到头部

1. 设定一个script标签
<script src="http://jsonp.js?callback=xxx"></script>
2. 服务器
$callback = !empty($_GET['callback'] ? $_GET['callback'] : 'callback');
echo $callback.'(.json_encode($data).)';

  详见博客 JSON 和 JSONP两兄弟

2. cors

方案对比
  JSONP CORS
目的 跨域 跨域
支持

get

(受IE下url长度不能超过2083个字节的限制和出于安全考虑,一般不用来提交数据)

所有类型的http请求
支持度 包括老式浏览器 不支持部分浏览器,移动端支持很好
缺点

1)安全问题(请求代码中可能存在安全隐患)

2)确定jsonp请求是否失败不太容易

3)只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题

支持率
原理

被包含在一个回调函数中的JSON

核心则是动态添加<script>标签来调用服务器提供的js脚本

(允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了)

使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败

(只需由服务器发送一个响应标头即可)

CORS需要浏览器和服务器同时支持

实现CORS通信的关键是服务器,只要服务器实现了CORS接口,就可以跨域通信


1)两种请求方式

  简单请求、非简单请求

  a)简单请求:

  

  

  跨域时,浏览器自动在头部信息中添加一个origin 字段(指定请求源-协议+域名+端口),如下图所示

  

  服务器判断origin在域名许可范围内,返回响应:

  

  若不存在 Access-Control-Allow-Origin 字段,则出错

  以上头部信息中,CORS相关字段有

  • Access-Control-Allow-Origin
    必须字段,其值为 origin / *(可接受任意域名请求)
  • Access-Control-Allow-Credentials
    可选,是否允许发送Cookie
  • Access-Control-Expose-Headers
    可选,是否需要Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma之外的字段

  withCredentials 属性

  CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段

Access-Control-Allow-Credentials: true

  另一方面,开发者必须在AJAX请求中打开withCredentials属性。

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

  注意

  如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

  b)非简单请求(不同时满足以上条件)

  请求方法是PUTDELETE,或者Content-Type字段的类型是application/json

  浏览器对于非简单请求,就自动发出一个"预检"请求,要求服务器确认可以这样请求。下面是这个"预检"请求的HTTP头信息

  

  

  除了Origin字段,"预检"请求的头信息包括两个特殊字段。

  • Access-Control-Request-Method

   该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT

  • Access-Control-Request-Headers

   该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header

2.CORS 支持度

3. document.domain

两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 Cookie。

举例来说,A网页是http://w1.example.com/a.html,B网页是http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享Cookie

document.domain = 'example.com';

现在,A网页通过脚本设置一个 Cookie

document.cookie = "test1=hello";

B网页就可以读到这个 Cookie。

var allCookie = document.cookie;

注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法,规避同源政策,而要使用下文介绍的PostMessage API。

4. iframe

 (只有在主域相同时才能使用)

  1)www.a.com/a.html中:

document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://www.script.a.com/b.html';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
//在这里操作doc,也就是b.html
ifr.onload = null;
};

  2) 在www.script.a.com/b.html中:

document.domain = 'a.com';

5. window.postMessage:

该方法是 HTML5 新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。

window.postMessage的功能是允许程序员跨域在两个窗口/frames间发送数据信息。基本上,它就像是跨域的AJAX,但不是浏览器跟服务器之间交互,而是在两个客户端之间通信

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);
}
}

【a.qq.com页面代码】

【b.qq.com页面代码】

以上demo简单解决了前端跨域通信,跨域带cookie等问题,在逻辑上完全可以实现跨域通信。但是对于不支持PostMessage特性的老版浏览器是行不通的。比如IE8-浏览器就不能很好的支持PostMessage特性

6. 服务端代理

在数据提供方没有提供对JSONP协议或者window.name协议的支持,也没有对其它域开放访问权限时,我们可以通过server proxy的方式来抓取数据。

例如当www.a.com域下的页面需要请求www.b.com下的资源文件asset.txt时,直接发送一个指向 www.b.com/asset.txt的ajax请求肯定是会被浏览器阻止。

这时,我们在www.a.com下配一个代理,然后把ajax请求绑定到这个代理路径下,例如www.a.com/proxy/, 然后这个代理发送HTTP请求访问www.b.com下的asset.txt,跨域的HTTP请求是在服务器端进行的,客户端并没有产生跨域的ajax请求。

这个跨域方式不需要和目标资源签订协议,带有侵略性,另外需要注意的是实践中应该对这个代理实施一定程度的保护,比如限制他人使用或者使用频率。

其他跨域方案

window.name:

在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的。

动态创建script

JSONP也就是利用这个原理。

利用iframe和location.hash

淘汰类技术

利用flash

淘汰类技术

参考链接:

http://tech.jandou.com/cross-domain.html

http://www.cnblogs.com/JChen666/p/3399951.html

http://www.ruanyifeng.com/blog/2016/04/cors.html

用HTML5里的window.postMessage在两个网页间传递数据

JSONP && CORS的更多相关文章

  1. 同源策略与 JSONP CORS

    同源策略与 JSONP CORS 同源策略 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以 ...

  2. vue—你必须知道的 js数据类型 前端学习 CSS 居中 事件委托和this 让js调试更简单—console AMD && CMD 模式识别课程笔记(一) web攻击 web安全之XSS JSONP && CORS css 定位 react小结

    vue—你必须知道的   目录 更多总结 猛戳这里 属性与方法 语法 计算属性 特殊属性 vue 样式绑定 vue事件处理器 表单控件绑定 父子组件通信 过渡效果 vue经验总结 javascript ...

  3. 跨域请求解决方法(JSONP, CORS)

    1.跨域 假设我们页面或者应用部署在 http://www.aaa.com 上了,而我们打算从 http://www.bbb.com 请求提取数据.一般情况下,如果我们直接使用 AJAX 来请求将会失 ...

  4. 跨域访问JSONP CORS

    一.JSONP 常用的Jquery框架支持jsonp方式请求,该方式只支持GET方法,传参大小有限,而且需要后台根据jsonp的请求方式进行封装结果返回. 其中参数jsonp默认为callback,j ...

  5. 004. 前端跨域资源请求: JSONP/CORS/反向代理

    1.什么是跨域资源请求? https://www.cnblogs.com/niuli1987/p/10252214.html 同源: 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有 ...

  6. 解决跨域问题-jsonp&cors

    跨域的原因 浏览器的同源策略 同源策略是浏览器上为安全性考虑实施的非常重要的安全策略. 指的是从一个域上加载的脚本不允许访问另外一个域的文档属性. 举个例子:比如一个恶意网站的页面通过iframe嵌入 ...

  7. 请求不同域的数据方法:requests Jsonp cors

    在需要访问不同域的接口的数据的时候,一般有两种方式: 第一种: 使用requests模块,在业务逻辑中直接访问别的域的接口,获取数据,然后将返回的数据显示到前端页面上; 这个时候,数据访问的流程是: ...

  8. 搞定所有的跨域请求问题 jsonp CORS

    网上各种跨域教程,各种实践,各种问答,除了简单的 jsonp 以外,很多说 CORS 的都是行不通的,老是缺那么一两个关键的配置.本文只想解决问题,所有的代码经过亲自实践.   本文解决跨域中的 ge ...

  9. 再也不学AJAX了!(三)跨域获取资源 ② - JSONP & CORS

    浏览器的"同源策略"固然保障了互联网世界的数据隐私与数据安全,但是如果当我们需要使用AJAX跨域请求资源时,"同源策略"又会成为开发者的阻碍.在本文中,我们会简 ...

随机推荐

  1. Newbit 启用淘宝店域名

    自2016-10-19起,我们正式启用淘宝店的域名,newbit.taobao.com 店里提供所有课程当中用到硬件,ZigBee插件/贴片模块等, 我们将坚持给大家提供最具扩展性,最方便使用的开发工 ...

  2. block的修饰词为什么选用copy

    想必很多开发人员知道一般用copy修饰block,接下来就讲解为什么需要用copy,甚至会讲到其实用strong修饰block也是可以的 在 Objective-C 语言中,一共有 3 种类型的 bl ...

  3. 算法-java代码实现基数排序

    基数排序 第11节 基数排序练习题 对于一个int数组,请编写一个基数排序算法,对数组元素排序. 给定一个int数组A及数组的大小n,请返回排序后的数组.保证元素均小于等于2000. 测试样例: [1 ...

  4. 什么是MVC ?

    记得第一次面试phper(php是对我来说可以快速上手的另一web开发语言),人家问我MVC,我只知道m就是model,v就是view,c就是Controller,具体把其它的认识我是一无所知,结果我 ...

  5. dedecms织梦网站图片集上传图片出现302错误图片提示怎么解决 已测

    时间:2016-01-20 来源:未知 作者:模板之家 阅读:次 小编今天上传织梦网站模板的时候,在图片集里面选择上传图片的时候,弹出302错误提示,当是真的是郁闷了,试了好几次,开始还以为是图片过大 ...

  6. 关于HTTP请求出现 405状态码 not allowed的解决办法

    最近学爬虫.发现httppost请求目标网站会出现405 状态码,原因为 Apache.IIS.Nginx等绝大多数web服务器,都不允许静态文件响应POST请求 所以将post请求改为get请求即可

  7. PHP flock() 函数

    定义和用法 flock() 函数锁定或释放文件. 若成功,则返回 true.若失败,则返回 false. 语法 flock(file,lock,block) 参数 描述 file 必需.规定要锁定或释 ...

  8. Phpstorm10 主题下载

    ================================================================================ submit:主题 http://ww ...

  9. Mac OS启动服务优化高级篇

    一.Mac下的启动服务主要三个可配置的地方 1.系统偏好设置->帐户->登陆项 2./System/Library/StartupItems 和 /Library/StartupItems ...

  10. Spring学习之路一

    Spring 官网:http://projects.spring.io/spring-framework/ Spring下载地址:https://repo.spring.io/simple/libs- ...