- 场景:跨域问题只存在于浏览器端,App和小程序不存在跨域问题。
- 产生原因:由于uni-app是标准的前后端分离模式,开发h5应用时如果前端代码和后端接口没有部署在同域服务器,就会被浏览器报跨域。
前后端分离的开发模式越来越流行,目前绝大多数的公司与项目都采取这种方式来开发,它的好处是前端可以只专注于页面实现,而后端则主要负责接口开发,前后端分工明确,彼此职责分离,不再高度耦合,但是由于这种开发模式将前后端项目分开来独立部署,所以将必不可免的会碰到跨域问题.
- 解决方案:uni-app官方推荐
使用HBuilderX中内置的浏览器
去预览,在内置的浏览器中不会存在跨域问题;但是要是在Chrome 浏览器中预览的话就会出现这个跨域问题,官方推荐使用安装Allow-Control-Allow-Origin: * 插件
的方式去解决。参考:uni-app H5跨域问题解决方案(CORS、Cross-Origin)。 - 拓展:在App、小程序等非H5平台,是不涉及跨域问题的。稍微例外的是iOS的wkWebview,在5+App,或uni-app的web-view组件及renderjs中,由于WKWebview限制也会产生跨域,这方面另见Appstore审核反馈废弃UIWebview APIs问题的说明。uni-app在App的普通js代码不运行在Webview下,不存在跨域问题。
1. 什么是跨域
跨域指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的(目前所有的浏览器都实行同源策略),是浏览器对javascript施加的安全限制。
- 同源策略:指协议、域名、端口都要相同,其中有一个不同都会产生跨域
- 跨域:指浏览器不能执行其他网站的脚本。(跨域限制访问,其实是浏览器的限制。)
例如:a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。
A站点 | B站点 | 分析 | 是否跨域 |
---|---|---|---|
http://www.123.com/index.html | http://www.123.com/server.php | 同源 | 否 |
http://www.123.com/index.html | https://www.123.com/server.php | 协议不同(http/https) | 是 |
http://www.123.com/server.php | http://www.456.com/server.php | 主域名不同(123/456) | 是 |
http://abc.123.com/index.htm | http://def.123.com/server.php | 子域名不同(abc/def) | 是 |
http://www.123.com:8080/index.html | http://www.123.com:8081/server.php | 端口不同(8080/8081) | 是 |
注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域;域名和域名对应的ip也属于跨域。
2. 部署时的跨域解决方案
(1) 方案1:最直接的,当然还是将前端代码和后端接口部署在同域的web服务器上。
(2) 方案2:由后台服务器配置策略,设为允许跨域访问。
Access-Control-Allow-Origin是HTML5中定义的一种解决资源跨域的策略。通过服务器端返回带有Access-Control-Allow-Origin标识的Response header,用来解决资源的跨域权限问题。即在服务器响应客户端的时候,带上Access-Control-Allow-Origin头信息:
- Access-Control-Allow-Origin: * //允许所有域名的脚本访问该资源
- Access-Control-Allow-Origin:www.google.com //允许特定的域名访问
如PHP添加响应头信息:
header("Access-Control-Allow-Origin: *");
3. 调试时的跨域解决方案
前端工程师调试时,运行起来的前端代码在uni-app自带的web服务器中,而不是部署在后台业务服务器上,此时就会遇到跨域。除了协调后端配置允许跨域,其实也可以自己解决跨域问题。共3种方案可选。
3.1 使用HBuilderX内置浏览器
内置浏览器:经过官方处理,不存在跨域问题,简单易用,推荐使用(需HBuilderX 2.6以上)。
使用:在打开页面后,点HBuilderX右上角的预览,即可打开内部浏览器;或者在运行菜单里选择运行到内置浏览器也可以。
3.2 配置webpack-dev-server代理
参考:配置指南
3.3 给浏览器安装跨域插件
(1) 当我们使用谷歌浏览器调试ajax请求的时候可能会遇到这两个问题:
- 跨域资源共享CORS:CORS是一种w3c标准,全称是"跨域资源共享(Cross-origin resource sharing)"。它允许浏览器向跨源服务器发出XMLHttpRequest请求,从而克服了同源使用的限制。(传统的Ajax请求只能获取在同一个域名下面的资源,但是HTML5打破了这个限制,允许Ajax发起跨域的请求。浏览器是可以发起跨域请求的,比如你可以外链一个外域的图片或者脚本;但是Javascript脚本是不能获取这些资源的内容的,它只能被浏览器执行或渲染。)
- 跨源读取阻塞 CORB:如果实际响应的内容与浏览器预期的内容有差异可能被CORB策略所阻止。
最常见的就是关于跨域资源共享的问题,也就是我们通常说的跨域。当我们本地服务器预览页面,使用ajax访问远程服务器的内容时就会请求失败,比如:本地预览的地址是:http://localhost:8080/,访问的接口地址是http://dcloud.io/api。
(2) 如果仅仅是为了本地预览,可以使用Chrome浏览器插件Allow-Control-Allow-Origin: *
来协助调试。
本插件并非万能,请仔细阅读与学习浏览器安全策略相关知识。本插件只能解决简单请求的跨域调试;对于非简单请求的OPTION预检请求以及线上服务器也有跨域需求的用户,需要服务端配合解决。即此插件适合本地调试使用,线上部署如果和接口不同域还需要服务端配合。
(3) 插件安装方式
(4) 若使用插件后跨域问题依旧存在。
- 分析:
uni-app
中manifest.json->h5->devServer
实际上对应webpack
的 devServer,鉴于 manifest 为 json 文件,故webpack.config.js->devServer
配置项下的简单类型属性均可在manifest.json->h5->devServer
节点下配置,funciton 等复杂类型暂不支持。参考:manifest.json官方配置文档和uniapp-admin。 - 解决:参考使用proxy配置反向代理的方式去实现跨域请求,未验证
5. 其他
如果资源是html页面,可通过如下设置 解决跨域问题
<meta http-equiv="Access-Control-Allow-Origin" content="*">