1. 同源策略
来源:由应用协议、域名、端口号三个要素决定
同源就是来源一致。
- 同源策略保证只有同源的应用才能访问一个应用内的信息,也就保护应用不被恶意(如XSS、 CSFR攻击)脚本袭击或窃取信息。
- 在这个策略下,web浏览器允许第一个页面的脚本访问第二个页面里的数据,但是也只有在两个页面有相同的源时。这个策略可以阻止一个页面上的恶意脚本通过页面的DOM对象获得访问另一个页面上敏感信息的权限。
2. 同源策略带来的限制
同源策略使得非同源的请求受到以下限制:
- 网络层面限制:AJAX请求不能互通
- 数据层面限制:cookie、localstorage、indexDB不能获取异源的
- DOM层面限制:dom不能获取和操作异源的
虽然这些限制是合理且必需的,但是有时候一些场景,需要我们能具备跨域的功能。
3. 跨域方案
3.1 利用html标签
已知有几个标签是允许跨域的:
- img标签
- a标签
- link标签
- script标签
3.1.1 JSONP
利用标签script,可以将回调函数和变量作为参数向后端发送get请求,后端拿到请求后,处理后将回调函数的调用返回给客户端,客户端接收到函数后,执行该函数。
【前端】
<html>
<script>
window.myCallback = (res)=>{ //这里为上一步定义的全局函数
console.log(res)
}
</script>
<script url="xxx?callback=myCallback">
//script标签的请求必须在写在定义全局函数之后
//这里需将全局函数的函数名作为参数callback的value传递
//这里callback这个键名是前后端约定好的
</script>
</body>
</html>
【后端】
前端收到的拼接代码,将作为script标签内的代码,直接执行。
3.2 CORS
尽管默认情况下浏览器禁止我们访问跨域资源,但是我们可以利用 CORS 放宽这种限制,在保证安全性的前提下访问跨域资源。
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing),他允许浏览器向跨源服务器发送XMLHttpRequest请求,从而克服啦 AJAX 只能同源使用的限制。
CORS要客户端和服务端一起配合完成,其中主要是
- 客户端发出跨域请求后,浏览器会自动向我们的 HTTP header 添加一个额外的请求头字段:Origin。
- 浏览器校验来源是否可靠,如果可靠, 服务器返回的 response 还需要加一些响应头字段,这些字段将显式表明此服务器是否允许这个跨域请求。这些字段以Access-Control-*形式,有:
-
- Access-Control-Allow-Origin :必选,客户端的url是否是服务端允许的
- Access-Control-Allow-Methods:客户端请求的方法是否是服务端所允许的
-
- Access-Control-Allow-Credentials :该字段可选, 表示是否可以发送cookie
- Access-Control-Expose-Headers :该字段可选,XHMHttpRequest对象的方法只能够拿到六种字段: Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma ,如果想拿到其他的需要使用该字段指定。
- 浏览器拿到Response,校验Access-Control-Allow-Origin是否与origin一致来判断是否接收跨域资源
3.3 postMessage
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
- 上面三个场景的跨域数据传递
3.4 websocket
Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。
websocket本身就没有同源策略,当然由于它具有可扩展性,你也可以将它扩展成为支持同源策略的协议。
3.5 Node的中间代理(正向代理)
实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略 。 代理服务器主要实现了转发浏览器请求和转发服务器的响应。
\
\
3.6 Ngnix(反向代理)
使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。
ngnix实现跨域有两种方式,一种是在后端配置,一种前端本地配置。
【后端使用ngnix解决跨域】
浏览器直接访问的是代理的地址,而不是直接访问源服务器的地址。
\
【前端使用ngnix解决跨域】
比如webpack启动的本地服务,端口号是8080,也就是localhost://8080,而这个地址不能跟服务端domain.com互通(因为跨域)。可以通过ngnix配置:
- ngnix将重新配置一个端口号为8081的,并且将这个代理到domain.com,使得localhost://8081可以和domain.com
- 同时将8081端口号, 代理到localhost://8080这个地址,这样子8081和8080两个端口也可以互通
- 见下面ngnix的配置之后,http://localhost /api 即可与domain.com互通
server {
listen 8081;
server_name localhost;
## 用户访问 localhost,则反向代理到https://api.shanbay.com
location / {
proxy_pass http://domain.com;
}
location /api/ {
proxy_pass http://localhost:8080;
}
}