在 BS 架构的项目中以及前端开拓编码过程中有可能会碰着跨域的问题,而跨域问题随着当代 web 开拓很多项目采取前后端分离的办法进行分工互助再一次成为前端开拓过程中都会碰着问题。曾经有一段韶光 JSONP 的一度成为很多跨域问题的办理方案。在个人印象中曾经有一段期间各个公司关注于建站建官网进行 SEO,那个时候很多开拓职员都会在前端粘贴一段脚本用来监控对网站的要求,那个时候跨域问题开始进入我个人的视野。后来随着 Vue、Angular、React 的兴起刮起了前端开拓变革的风,前后分离的开拓办法让跨域问题再一次成为须要面对的问题。
所谓跨域问题实际上便是浏览器的一个非常核心的安全策略,有很多方法可以来办理这个问题,各个方法利用场景各不相同。在项目中有有利用过几个办理方案,在这里做归纳总结
在前端开拓编码过程中,常见的 html 标签例如:a、form、img、script、link、iframe以及 Ajax 操作都可以指向一个资源地址或者说可以发起对一个资源的要求,那么这里所说的要求就存在同域要求还是跨域要求。

所谓跨域要求便是指:当条件议要求的域与该要求指向的资源所在的域不一致(这里所有的域是协议、域名和端口号的合集,同域便是所协议、域名和端口号均相同,任何一个不同都是跨域)。
常见的跨域场景有:
常见的跨域场景
同源策略(same-origin pllicy)同源策略是由 Netscape 提出的一个著名的安全策略,它是浏览器最基本最核心的安全功能。如果短缺了同源策略,则浏览器的正常功能都会受到影响,可以说 web 是构建在同源策略根本上的,浏览器是针对同源策略的一种实现。
同源策略是浏览器的行为,是为了保护本地数据不被 Javascript 代码获取回来的数据污染,因此拦截的是客户端发出要求后回来的数据吸收,即要求发送了,做事器相应了,但无法被浏览器吸收实行,在当代浏览器中违反同源策略的跨域要求会在掌握台直接报错。
chrome掌握台报错信息
同源策略的详细表现:
DOM 层面的同源策略,限定了来自不同源的Document工具或者 JS 脚本对当前Document工具的读取或设置某些属性Cookie 和 XMLHttpRequest 层面的同源策略,默认情形下禁止 Ajax 直接进行跨域要求(要求可以发起,但吸收结果等操作被浏览器拦截并在掌握台报错),cookie 层面数据默认不能跨域访问特定 HTML 标签的的策略,a、form、img、script、link、iframe等这些有src属性的标签可以对资源跨域访问和实行为什么会有这些限定
同源策略是浏览器最核心根本的一个安全策略,是浏览器基于安全的须要来进行的限定。常见的CSRF、XSS攻击都与之有关联。在这里就不做先容,有兴趣的读者可以自行去搜索理解下这些攻击的事理
跨域要求为什么会涌如今前端开拓中?既然同源策略是浏览器的核心根本安全策略,那为什么我们在进行前端开拓特殊是 Ajax 调用时还要进行跨域要求呢?同源策略是用来防御来自造孽的攻击,但我们不能由于防御造孽的攻击就将所有的跨域都拦截掉。
在当代前端开拓中,我们常常须要调用第三方的做事接口(例如 mock server、fake api),随着专业化分工的涌现有很多专业的信息做事供应商为前端开拓者供应各种接口,这种情形下就须要进行跨域要求(这类前端接口做事很多是采取的 cors 办法来办理跨域问题的,下文会详细先容)。
还有一类情形是在前后端分离的项目中,前端后端分属于不同的做事跨域问题在采取这种架构的时候就存在。而且现在很多项目都采取这种前后分离的办法,这类项目很多是会采取反向代理的办法来办理跨域问题。
Ajax 跨域要求如何实现这里所说的跨域要求办理方案紧张是针对 Ajax 要求
修正浏览器的安全设置(不推举)
既然是浏览器的安全策略,那么最大略粗暴的方法便是禁用这个策略。这种操作很危险,不推举利用。在此也不做详细的先容,在跨域问题刚出来的时候有人采取这种方法,目前已很少有人采取。
JSONP
JSONP(JSON with Padding)是 JSON 的一种利用模式,可用于办理主流浏览器的跨域数据访问问题,在早两三年前端办理跨域问题中常常涌现这类办理方案。
JSONP 的事理便是,Ajax 存在跨域安全问题但是 script 标签是不存在这类问题的,于是乎就有人根据这个特性做文章找办理方案。
remote.com/remote.js
remoteFunction('remote)
index.html
<script src=\"大众http://remote.com/remote.js\"大众 type=\"大众text/javascript\"大众></script><script>remoteFunction()</script>
我们都知道这种办法是可以成功的,因此进一步改造:
remote.com/remote.js
let data = { code: 200, msg: \公众data from remote\"大众};localFunction(data);
index.html
<script>localFunction(data) { console.log(data)}</script><script src=\"大众http://remote.com/remote.js\"大众 type=\公众text/javascript\"大众></script>
通过这一步的改造就可以创造我们确当地函数的参数是来自于远程做事,在远程 remote.js 根据业务逻辑通报参数到本地函数进行的调用。
于是更进一步,将代码写去世的 remote.js 进行动态的天生,我们往后台 PHP 措辞为例:
remote.php
<?php//通过设置content-type能够指明返回的内容类型header('Contetn-type:application/json');$callbackFunction = htmlspecialchars($_GET['callback']);$data = 'data from remote';echo $callbackFunction.'('.$data.')';
index.html
<script type=\公众text/javascript\"大众> localFunction = function(data) { console.log(data); };</script><script src=\"大众http://localhost:3000/remote.php?callback=localFunction\公众 type=\公众text/javascript\公众></script>
这种实现办法便是 JSONP 的大略实现,JSONP 的核心理念便是利用 script 可以进行跨域要求,通过跨域要求将业务处理逻辑的回调函数通过 url 参数的形式发给远程要求,远程要求通过数据库调用获取到前端须要的数据后,将发送过来的回掉函数以及数据参数进行拼装,天生一段可实行的 JavaScript(json)代码,这样当这次要求完成后,对应的业务处理函数也就对应的实行了。
JSONP 有其天然的毛病,由于是通过 script 的 src 进行的资源要求,以是都是 GET 办法,其他的 POST、PUT、DELETE 并不支持。这种采取这种办理办法越来越少。
跨域资源共享 CORS(Cross-Origin Resource Sharing)
CORS 是一个新的 W3C 标准,它新增的一组 HTTP 首部字段许可做事器其声明哪些来源要求有权限访问哪些资源,换言之它许可浏览器向其声明了 CORS 的站进行跨域要求。
这种办法最紧张的特点便是会在相应的 HTTP 首部增加 Access-Control-Allow-Origin 等信息,从而剖断哪些资源站可以进行跨域要求,还有几个其他干系的 HTTP 首部进行更加风雅化的掌握,最紧张的还是 Access-Control-Allow-Origin。详细每个首部信息的含义可以去搜索详细理解下。
我们以 Express 搭建的远程做事为例来解释:
var express = require(\"大众express\"大众);var cors = require(\"大众cors\公众);var app = express();//利用express的cors中间件使其支持跨域要求app.use(cors());app.get(\"大众/\"大众, function(req, res, next) { res.json({ msg: \"大众This is CORS-enabled for all origins!\"大众 });});app.listen(3000, function() { console.log(\"大众CORS-enabled web server listening on port 80\"大众);});
针对支持 CORS 的做事发起 Ajax 要求最大的特定,客户端即浏览器首先会发送一次要求到做事端判断做事端是否支持跨域要求及是否合法,如果判断通过会回答信息给客户端浏览器,浏览器通过收到的回答信息判断做事端对这次跨域要求是否支持,如果支持就再发送实际的业务要求。以是在这里会有两次要求。
CORS 与 JSONP 比拟来说上风比较明显,JSONP 只支持 GET 办法局限性很多,而且 JSONP 并不符合处理业务的正常流程。采取 CORS 的办法,前端编码与正常非跨域要求没有什么不同。在目前很多的 Fake API (仿照接口做事)、Mock Server(数据仿照做事)以及其他公共做事上都很多采取 CORS 的办法来办理跨域问题,例如 json-server 等。
iframe
iframe 与 JSONP 都是利用 src 属性没有跨域限定的特性,iframe 这种办法也不推举利用,不做详细先容。
反向代理
既然不能跨域要求,那么我们不跨域就可以了。通过在要求到达做事前支配一个做事,将接口要求进行转发,这便是反向代理。通过一定的转发规则可以将前真个要求转发到其他的做事。以 Nginx 为例:
server { listen 9999 server_name localhost #将所有localhost:9099/api为开头的要求进行转发 location ^~ /api { proxy_pass http://localhost:3000; }}
通过反向代理我们将前端后端项目统一通过反向代理来供应对外的做事,这样在前端看上去就跟不存在跨域一样。
反向代理麻烦之处就在原对 Nginx 等反向代理做事的配置,在目前前后端分离的项目中很多都是采取这种办法。
总结综上所述,CORS 和反向代理是目前利用最多的办理方案,这两个办理方案利用的场景并不相同,我们要根据自身的需求进行选择。公共做事、Fake API 、Mock Server 一样平常采取 CORS 的方案;而公司前后端分离的项目中更多是采取反向代理的方案。