跨域
跨域关键知识:
- 同源策略。浏览器故意设计的一个功能限制
 - CORS。突破浏览器限制的一个方法
 - JSONP。IE 时代的妥协
 
同源
源 = 协议 + 域名 + 端口号
window.origin 或 location.origin 可以得到当前源。
如果两个 url 的协议、域名、端口号完全一致,那么这两个 url 就是同源。
例:https://qq.com 和 https://www.baidu.com     不同源
https://baidu.com 和 https:www.baidu.com     同源
完全一致才算同源
下表给出了与 URL http://store.company.com/dir/page.html 的源进行对比的示例:
| URL | 结果 | 原因 | 
|---|---|---|
http://store.company.com/dir2/other.html | 
同源 | 只有路径不同 | 
http://store.company.com/dir/inner/another.html | 
同源 | 只有路径不同 | 
https://store.company.com/secure.html | 
失败 | 协议不同 | 
http://store.company.com:81/dir/etc.html | 
失败 | 端口不同 ( http:// 默认端口是80) | 
http://news.company.com/dir/other.html | 
失败 | 主机不同 | 
同源策略
Ajax 最大的限制是同源策略(Same-origin policy),它限制了不同源之间的交互,一个源的文档或脚本不能与另一个源的资源进行交互。浏览器的同源策略 MDN
浏览器规定
如果 JS 运行在源 A 里,那么就只能获取源 A 的数据
不能获取源 B 的数据,即==不允许跨域==
例如(省略 http 协议)
假设 frank.com/index.html 引用了 cdn.com/1.js
那么就说 1.js 运行在源 frank.com 里
注意 这跟 cdn.com 没有关系,虽然 1.js 从它哪下载
所以 1.js 就只能获取 frank.com 的数据
不能获取 1.frank.com 或者 qq.com 的数据
这是浏览器的功能
浏览器故意要这样设计的
目的:==保护用户隐私==
如果没有同源策略
以 qq 空间为例
源为 https://user.qzone.qq.com,假设,当前用户已登录(cookie),假设 AJAX 请求 /friends.json 可获取到用户好友列表。
黑客来了,假设有人给你分享 https://qzone-qq.com  给你,实际上是个钓鱼网站,你点开后,这个网页会请求你的好友列表 https://user.qzone.qq.com/friends.json。这样好友列表就能被黑客访问到。
问题根源:
无法区分发送者
qq 空间页面的 JS 和黑客网页里的 JS 发送的请求几乎没有区别(referrer 有区别)
如果后台开发者没有检查 referrer,那么就完全没有区别
所以,没有同源策略,任何页面都能偷 qq 空间的数据
那检查 referrer 不就好了
安全原则:安全链条的强度取决于最弱的一环
万一这个网站的后端开发工程师就是没有检查 referrer
所以浏览器应该主动预防这种偷数据的行为
总之,浏览器为了用户隐私,设置了严格的同源策略
演示
创建目录
qq-com 里新建 server.js,用来模拟 qq空间
frank-com 里新建 server.js,用来模拟黑客网站
qq-com
public 目录下新建 index.html 首页
qq.js 是 JS 脚本文件
friends.json 是模拟的好友数据
端口监听为 8888,访问
http://127.0.0.1:8888hacker-com
public 目录下新建 index.html 首页
frank.js 是 JS 脚本文件
端口监听为 9999,范问
http://127.0.0.1:9999
跨域 AJAX
正常使用 AJAX
在 qq.com:8888 里运行的 JS 可以访问 /friends.json

能够访问 黑客偷数据
在 hacker.com:9999 里运行的 JS不能访问
浏览器需要==CORS==

提问
黑客的请求成功了没:
答:成功了,因为 qq.com 后台有 log。
黑客拿到响应了没与?
答:没有,因为浏览器不给数据。

如何跨域
CORS
CORS 是一个 W3C 标准,全称是”跨域资源共享”(Cross-origin resource sharing)。
问题根源
浏览器默认不同源之间不能互相访问数据
但是 qq.com 和 hacker.com 都是自己的网站,需要互相访问
用 CORS
浏览器说,如果要共享数据,需要提前声明!
qq.com 在响应头里写 hacker.com 可以访问
语法:
Access-Control-Allow-Origin: http://hacker.com:9999
CORS 不兼容 ie 6789
JSONP
什么是 JSONP?
跨域时,由于当前浏览器不支持 CORS 或因为某些条件不支持 CORS,我们必须使用另外一种方式来跨域。
于是,请求一个 JS 文件,这个 JS 文件会执行事先定义好的回调,这个回调里就有我们需要的数据。
优点:
- 支持 IE
 
缺点:
- 由于是 script 标签,获取不到响应状态
 - 不支持 POST
 
演示:hacker.com 访问 qq.com
- qq.com 将数据写到 /friends.js
 - frank.com 用 script 标签引用 /friends.js
 - hacker.com 执行 事先定义好的 window.xxx 函数
 - /friends.js 执行 window.xxx({friend: […]})
 - 然后 hacker.com 就通过 window.xxx 获取到数据了
 - window.xxx 就是一个回调!!
 
JSONP 的实现原理演示:
hacker-com 里的 hacker.js
1  | window.xxx = (data) => {  | 
qq-com public目录下新建 friends.js 内容为 window.xxx ( {{ data }} )
qq-com 的 server.js 添加如下路由
1  | else if (path === '/friends.js') {  | 
优化:
window.xxx 能不能改其他名字?
其实名字不重要,只要 hacker.com 定义的函数名和 qq.com/friends.js 执行的函数名是同一个即可。
将名字穿给 /friends.js
1  | // hacker.js  | 
1  | // server.js  | 
1  | // friends.js  | 
进一步优化
1  | // hacker.js  | 
1  | // server.js  | 
JSONP 的本质是前后端的协作,即前端把想要的资源以及后续的处理都告诉后台,后台封装好返回给前端执行。
优质博客: