这是一个老生常谈的话题,以前我觉得这种基础文章没有什么好写的,最近为了线上问题深入了解底层,确实有点东西,下面汇总成10种方案。
重要的说明: 在文中,web 端地址为 localhost:8000 服务端地址为 localhost:8080,这一点希望你能记住,会贯穿全文,你也可以把此处的两端的地址代入你自己的地址。
以下所有代码均在https://github.com/hua/node-demo/tree/master/node-cors
跨域问题其实就是浏览器的同源策略所导致的。
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。--来源 MDN
当跨域时会收到以下错误
那么如何才算是同源呢?先来看看 url 的组成部分
只有当
protocol(协议)、domain(域名)、port(端口)三者一致。
protocol(协议)、domain(域名)、port(端口)三者一致。
protocol(协议)、domain(域名)、port(端口)三者一致。
才是同源。
以下协议、域名、端口一致。
http://www.example.com:80/a.js
http://www.example.com:80/b.js
以下这种看上去再相似也没有用,都不是同源。
http://www.example.com:8080
http://www2.example.com:80
在这里注意一下啊,这里是为了突出端口的区别才写上端口。在默认情况下 http 可以省略端口 80, https 省略 443。这别到时候闹笑话了,你和我说http://www.example.com:80和http://www.example.com不是同源,他俩是一个东西。
http://www.example.com:80===http://www.example.com
https://www.example.com:443===https://www.example.com
唔,还是要说明一下。
跨域资源共享(CORS) 是一种机制,它使用额外的HTTP头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
而在 cors 中会有和的概念。
浏览器支持情况
当你使用 IE<=9, Opera<12, or Firefox<3.5 或者更加老的浏览器,这个时候请使用 JSONP 。
a.简单请求
不会触发CORS 预检请求。这样的请求为“简单请求”,请注意,该术语并不属于Fetch(其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:
情况一: 使用以下方法(意思就是以下请求意外的都是非简单请求)
情况二: 人为设置以下集合外的请求头
- (需要注意额外的限制)
情况三:的值仅限于下列三者之一:(例如 application/json 为非简单请求)
情况四:
请求中的任意对象均没有注册任何事件监听器;对象可以使用属性访问。
情况五:
请求中没有使用对象。
b.非简单请求
除以上情况外的。
c.Node 中的解决方案
原生方式
我们来看下后端部分的解决方案。中的解决代码.
第三方中间件
为了方便也可以直接使用中间件
golang中使用:
关于 cors 的 cookie 问题
想要传递需要满足 3 个条件
1.web请求设置
这里默认情况下在跨域请求,浏览器是不带 cookie 的。但是我们可以通过设置来进行传递.
2.为
3.为非
这里请求的方式,在中是能看到返回值的,但是只要不满足以上其一,浏览器会报错,获取不到返回值。
d.前端示例
分别演示一下前端部分和
简单请求
非简单请求
这里我们加入了一个非集合内的头来达到非简单请求的目的。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的请求,否则就报错。
"预检"请求用的请求方法是,表示这个请求是用来询问的。头信息里面,关键字段是,表示请求来自哪个源。
除了字段,"预检"请求的头信息包括两个特殊字段。
(1)Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是。
(2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是。
服务器收到"预检"请求以后,检查了、和字段以后,确认允许跨源请求,就可以做出回应。
上面的HTTP回应中,关键的是字段,表示可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。
如果服务器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被对象的回调函数捕获。控制台会打印出如下的报错信息。
服务器回应的其他CORS相关字段如下。
小结
1、 在新版的 chrome 中,如果你发送了复杂请求,你却看不到请求。可以在这里设置设置成,或者升级到最新版本chrome,重启浏览器。对于非简单请求就能看到请求了。
2、 一般情况下后端接口是不会开启这个跨域头的,除非是一些与用户无关的不太重要的接口。
一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个头信息字段。服务器的回应,也都会有一个头信息字段。
下面是"预检"请求之后,浏览器的正常CORS请求。
上面头信息的字段是浏览器自动添加的。
下面是服务器正常的回应。
上面头信息中,字段是每次回应都必定包含的。
代理的思路为,利用服务端请求不会跨域的特性,让接口和当前站点同域。
这样,所有的资源以及请求都在一个域名下了。
a.cli 工具中的代理
1) Webpack (4.x)
在中可以配置来快速获得接口代理的能力。
修改前端接口请求方式,改为不带域名。(因为现在是同域请求了)
2) Vue-cli 2.x
3) Vue-cli 3.x
4) Parcel (2.x)
看到这里,心里一句 xxx 就会脱口而出,一会写配置文件,一会 proxyTable ,一会 proxy,怎么这么多的形式?学不动了学不动了。。。不过也不用慌,还是有方法的。以上所有配置都是有着共同的底层包http-proxy-middleware.里面需要用到的各种,等功能,直接看这个库的配置就可以了。关于 http-proxy-middleware 这个库的原理可以看我这篇文章https://github.com/hua/proxy当然了。。。对于配置的位置入口还是非统一的。教一个搜索的技巧吧,上面配置写哪里都不用记的,想要哪个框架的 直接 google 搜索 xxx proxy 就行了。
例如 vue-cli 2 proxy 、 webpack proxy 等等....基本会搜到有官网的配置答案,通用且 nice。
b.使用自己的代理工具
cors-anywhere
服务端
前端代码
效果展示
缺点
无法专递 cookie,原因是因为这个是一个代理库,作者觉得中间传递 cookie 太不安全了。https://github.com/Rob--W/cors-anywhere/issues/208#issuecomment-
c.charles
介绍
这是一个测试、开发的神器。介绍与使用
利用 charles 进行跨域,本质就是请求的拦截与代理。
在中设置代理
前端代码
后端代码
效果
访问http://localhost:8000/charles
完美解决。
唔。这里又有一个注意点。在中会出现抓不到本地包的情况。这个时候需要自定义一个域名,然后配置指定到。然后修改访问方式。
介绍
Nginx 则是通过反向代理的方式,(这里也需要自定义一个域名)这里就是保证我当前域,能获取到静态资源和接口,不关心是怎么获取的。nginx 安装教程
配置下 hosts
配置 nginx
启动 nginx
重启 nginx
实现
前端代码
后端代码
效果
访问
主要就是利用了标签没有跨域限制的这个特性来完成的。
使用限制
仅支持 GET 方法,如果想使用完整的 REST 接口,请使用 CORS 或者其他代理方式。
流程解析
1.前端定义解析函数(例如 jsonpCallback=function(){....})
2.通过 params 形式包装请求参数,并且声明执行函数(例如 cb=jsonpCallback)
3.后端获取前端声明的执行函数(jsonpCallback),并以带上参数并调用执行函数的方式传递给前端。
使用示例
后端实现
普通 js 示例
JQuery Ajax 示例
原理解析
其实这就是 js 的魔法
我们先来看最简单的 js 调用。嗯,很自然的调用。
我们稍稍改造一下,外链的形式。
我们再改造一下,我们把这个外链的 js 就当做是一个动态的接口,因为本身资源和接口一样,是一个请求,也包含各种参数,也可以动态化返回。
你仔细品,细细品,是不是 jsonp 有的优势就是 script 加载 js 的优势,加载的方式只不过换了一种说法。这也告诉我们一个道理,很多东西并没有那么神奇,是在你所学的知识范围内。就好比,桃树和柳树,如果你把他们当成很大跨度的东西去记忆理解,那么世上这么多树,你真的要累死了,你把他们都当成是树,哦吼?你会突然发现,你对世界上所有的树都有所了解,他们都会长叶子,光合作用....当然也有个例,但是你只需要去记忆这些细微的差别,抓住主干。。。嗯,反正就这么个道理。
WebSocket规范定义了一种 API,可在网络浏览器和服务器之间建立“套接字”连接。简单地说:客户端和服务器之间存在持久的连接,而且双方都可以随时开始发送数据。详细教程可以看https://www.html5rocks.com/zh/tutorials/websockets/basics/
这种方式本质没有使用了 HTTP 的响应头, 因此也没有跨域的限制,没有什么过多的解释直接上代码吧。
前端部分
后端部分
window.postMessage()方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage()方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
用途
1.页面和其打开的新窗口的数据传递
2.多窗口之间消息传递
3.页面与嵌套的 iframe 消息传递
用法
详细用法看https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
- otherWindow: 其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
- message: 将要发送到其他 window 的数据。
- targetOrigin: 通过窗口的 origin 属性来指定哪些窗口能接收到消息事件.
- transfer(可选) : 是一串和 message 同时传递的对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权
示例
index.html
another.html
从第 7 种到第 9 种方式,我觉得别人的写的已经很好了,为了完整性,我就拿别人的了。如有雷同....(不对,就是雷同....)不要说不出来。
该方式只能用于二级域名相同的情况下,比如和适用于该方式。 只需要给页面添加表示二级域名都相同就可以实现跨域。
实现原理
原理就是通过 url 带 hash ,通过一个非跨域的中间页面来传递数据。
实现流程
一开始 a.html 给 c.html 传一个 hash 值,然后 c.html 收到 hash 值后,再把 hash 值传递给 b.html,最后 b.html 将结果放到 a.html 的 hash 值中。 同样的,a.html 和 b.htm l 是同域的,都是,而 c.html 是
window 对象的 name 属性是一个很特别的属性,当该 window 的 location 变化,然后重新加载,它的 name 属性可以依然保持不变。
其中 a.html 和 b.html 是同域的,都是,而 c.html 是
b.html 为中间代理页,与 a.html 同域,内容为空。
通过 iframe 的 src 属性由外域转向本地域,跨域数据即由 iframe 的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
其实讲下其实跨域问题是浏览器策略,源头是他,那么能否能关闭这个功能呢?
答案是肯定的。
注意事项: 因为浏览器是众多 web 页面入口。我们是否也可以像客户端那种,就是用一个单独的专门宿主浏览器,来打开调试我们的开发页面。例如这里以 chrome canary 为例,这个是我专门调试页面的浏览器,不会用它来访问其他 web url。因此它也相对于安全一些。当然这个方式,只限于当你真的被跨域折磨地崩溃的时候才建议使用以下。使用后,请以正常的方式将他打开,以免你不小心用这个模式干了其他的事。
Windows
Mac
这个目录可以自定义.
效果展示
嗯,使用起来很香,但是再次提醒,一般情况千万别轻易使用这个方式,这个方式好比七伤拳,使用的好威力无比,使用不好,很容易伤到自己。
在最一开始,我们知道了,跨域只存在于浏览器端。而浏览器为 web 提供访问入口。我们在可以浏览器内打开很多页面。正是这样的开放形态,所以我们需要对他有所限制。就比如林子大了,什么鸟都有,我们需要有一个统一的规范来进行约定才能保障这个安全性。
这里还是用最常用的方式来讲解,例如用户登录 a 网站,同时新开 tab 打开了 b 网站,如果不限制同源, b 可以像 a 网站发起任何请求,会让不法分子有机可趁。
如果可以进行 dom 操作...那么大家的信息在这种钓鱼网站眼里都是一颗颗小白菜,等着被收割。
可以在 http 返回头 添加防止被别人添加至 iframe。
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
以上最常用、最重要的是CORS、代理、JSONP,我里面也提到了多种示例,大家可以慢慢消化一下。希望未来有更加安全的方式来限制 web ,解决跨域的头疼,哈哈。
参考:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
https://www.ruanyifeng.com/blog/2016/04/cors.html
到此这篇前端跨域解决方案(前端跨域解决方案cors设置星号)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/qdkf/30452.html