解决 ionic 中的 CORS(跨域)
译者注:本人翻译功力有限,所以文中难免有翻译不准确的地方,凑合看吧,牛逼的话你看英文版的去,完事儿欢迎回来指正交流(^_^)
如果你通过 ionic serve
或者 ionic run
命令使用或 live reload 或者访问过外部 API 结点,那么你肯定遇到过 CORS 问题,譬如下面这样:
XMLHttpRequest cannot load http://api.ionic.com/endpoint.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:8100' is therefore not allowed access.
那么问题来了,什么是 CORS 呢?又是什么导致了这个问题嘞?
什么是 CORS?
CORS=Cross origin resource sharing(跨域资源共享)
origin
就是你现在正在看的主站,你现在访问的是 http://ionicframework.com/blog/handling-cors-issues-in-ionic
,那么 origin
就是 ionicframework.com
。
如果说我们向 http://cors.api.com/api
发起一个 AJAX 请求,那么 host origin 会由被浏览器自动列入CORS请求的 Orgin header 指定好了*(原文:Say we send an AJAX request to http://cors.api.com/api, your host origin will be specified by the Origin header that is automatically included for CORS requests by the browser. )* 由于 ionicframework.com
和 api.com
的主机并不匹配,所以在一个HTTP OPTIONS请求报头的 form 中我们所有从 ionicframework.com
发起的访问服务器资源的请求必修得到服务器的授权。
假如上面的请求出现错误(不被服务器允许),那么我们是无法从服务器访问到(api.com
上的)资源的。
让我们来看一下当你通过ionic serve
, ionic run
,ionic run -l
来运行 app 的时候 origin
会是什么。
浏览器中的运行
当你运行 ionic serve
时发生了什么呢?
- 启动了一个本地 web 服务器
- 你的浏览器打开并定位到本地服务器地址
这让你看着你的应用加载到你电脑上一个浏览器里,地址是:http://localhost:8100
(如果你选择了 localhost的话)。
你的 origin
就是 localhost:8100
。
任何的发送到其他不是 localhost:8100
主机上的 AJAX 请求都会把localhost:8100
作为他的 origin,这就会导致必须要经过一个 CORS 预检来看是否可以访问(非本机的)服务器资源。
设备上的运行
当你运行 ionic run
时发生了什么呢?
- app 所有的文件被拷贝到设备(或者模拟器)上。
- app 运行起来,触发手机/模拟器上的浏览器访问已经被拷贝上去的文件,比如:
file://some/path/www/index.html
。
因为你正在运行的 URI 是 file://
,所以你的 origin
将不会存在,所以任何向外的请求都不再需要 CORS 请求。
在设备使用 livereload 运行
当你运行 ionic run -l
时又发生了什么呢?
- 启动了一个本地服务器
- app 运行起来,触发手机/模拟器上的一个浏览器通过
http://192.168.1.1:8100
来运行文件(你的 本地 ip 可能是其他的)。
你的 origin
就会是 192.168.1.1:8100
。
任何一个发送到不是192.168.1.1:8100
的服务器上的 AJAX 请求都会需要进行 CORS 预检请求来看是否可以访问到该服务器上的资源。
在 ionic 中解决 CORS 问题
CORS 问题只有在我们通过 ionic serve
或者 ionic run -l
来运行或测试应用的时候才会遇到。
解决这个问题有两个办法:第一个,也是比较简单的一个,就是在你的 API 服务器端允许所有的 origin,然而我们并不能控制我们访问的所有的结点。我们需要的是一个不指定origin
的请求。
我们可以通过使用代理服务器来解决这个问题。我们来看看 Ionic CLI 是怎样提供了一个易配置的代理服务器的。
Ionic CLI代理服务器
关于代理的快速定义:
在计算机网络中,代理服务器就是一个服务器(计算机系统或者应用程序),是客户端发起的请求从其他服务器寻求资源的中间桥梁。
原文:In computer networks, a proxy server is a server (a computer system or an application) that acts as an intermediary for requests from clients seeking resources from other servers.
我们为了避开 CORS 问题需要做的就是有一个代理服务器,可以接收我们的请求,想 API 结点发出一个新的请求,接收结点响应,之后反馈给我们的应用,从而避开 CORS 问题。
Ionic CLI 就有给你提供一个代理服务器从而避开所有可能会遇到的 CORS 问题的能力。
由于代理服务器向你的目标主机发起了一个新的请求,所以就不会再有 origin
,也就不再需要 CORS 了。要注意,在浏览器增加了 Origin header 是很重要的。
设置代理服务器
注意,这些设置只有通过ionic serve
和 ionic run -l
运行应用才需要
首先我们需要在 ionic.project
文件中设置我们的代理,这会告诉我们的 Ionic 本地服务器监听这些地址,然后发送这些请求到我们的目标地址上。
在我们的应用中,当运行 serve
或 run -l
时候,我们需要把要访问的结点地址替换成代理服务器的地址。
使用gulp任务的 replace 模块来转换出口地址会简单一点。
建议的方法是设置一个 Angular Constant 来定位到我们试图代理的 API。
这就是我们下面要采用的方法。我们会同时设置一个 Angular Service 来从 API结点 获取数据。
设置代理路径
比如说我们想要访问 http://cors.api.com/api
,但并不允许我们来自 localhost
的 origin。
代理的设置包括两件事儿:在你本地 Ionic 服务器需要访问的 path
,最终需要访问API的 proxyUrl
。
在你的 ionic.project
中像这样设置:
{
"name": "proxy-example",
"app_id": "",
"proxies": [
{
"path": "/api",
"proxyUrl": "http://cors.api.com/api"
}
]
}
通过ionic serve
启动你的服务器。
像我们上面指定的这样,当你访问 Ionic 服务器地址 http://localhost:8100/api
的时候,它会以你的名义访问 http://cors.api.com/api
。
这样,就不需要 CORS 了。
设置 Angular Constant
把你的 API结点设置成 Angular Constants是非常简单的一件事儿。
下面我们就来把API结点指定成为我们的代理 URL。
之后(发布时候)我们会把正式的地址作为 constant。
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])
.constant('ApiEndpoint', {
url: 'http://localhost:8100/api'
})
// For the real endpoint, we'd use this
// .constant('ApiEndpoint', {
// url: 'http://cors.api.com/api'
// })
设置好之后你就能像下面这样在应用中引入ApiEndpoint
依赖,随意调用这个constant了。
设置Angular Service
angular.module('starter.services', [])
//NOTE: We are including the constant `ApiEndpoint` to be used here.
.factory('Api', function($http, ApiEndpoint) {
console.log('ApiEndpoint', ApiEndpoint)
var getApiData = function() {
return $http.get(ApiEndpoint.url + '/tasks')
.then(function(data) {
console.log('Got some data: ', data);
return data;
});
};
return {
getApiData: getApiData
};
})
通过 Gulp 自动转换地址
这个过程中,我们需要修改gulpfile.js
来添加两个任务:添加代理和移除代理。
首先安装replace
模块 - npm install --save replace
// `npm install --save replace`
var replace = require('replace');
var replaceFiles = ['./www/js/app.js'];
gulp.task('add-proxy', function() {
return replace({
regex: "http://cors.api.com/api",
replacement: "http://localhost:8100/api",
paths: replaceFiles,
recursive: false,
silent: false,
});
})
gulp.task('remove-proxy', function() {
return replace({
regex: "http://localhost:8100/api",
replacement: "http://cors.api.com/api",
paths: replaceFiles,
recursive: false,
silent: false,
});
})
结语
本教程向你展示了一个解决通过ionic serve
或ionic run -l
命令运行应用时候遇到的 CORS 问题的方法。
我们知道在ionic serve
和ionic run -l
之间转换 API 结点地址的时候可能会是个麻烦,比较建议的方法是启动一个 gulp 进程。
解决 CORS 问题最简单的方法是让 API 提供者允许所有的 hosts,然后这事儿有点儿不太现实。
使用 Angular constant 和 replace 模块可以给我们一个避开 CORS 的折中的办法。
如果你想看看完整的例子,可以看看这个示例项目。
这就是你需要访问一个有 CORS 限制的 API 服务器时候需要了解的所有事儿了。
如果你还有什么疑问、问题或者想法,请在下面评论,或者在 twitter 或 github 上联系我们。
解决 ionic 中的 CORS(跨域)的更多相关文章
- 如何在ASP.NET Core中实现CORS跨域
注:下载本文的完整代码示例请访问 > How to enable CORS(Cross-origin resource sharing) in ASP.NET Core 如何在ASP.NET C ...
- Spring Boot 2中对于CORS跨域访问的快速支持
原文:https://www.jianshu.com/p/840b4f83c3b5 目前的程序开发,大部分都采用前后台分离.这样一来,就都会碰到跨域资源共享CORS的问题.Spring Boot 2 ...
- 在ASP.NET Web API中实现CORS(跨域资源共享)
默认情况下,是不允许网页从不同的域访问服务器资源的,访问遵循"同源"策略的原则. 会遇到如下的报错: XMLHttpRequest cannot load http://local ...
- 在node中通过cors跨域。
cors : 全称 cross origin resource share 跨资源共享 在nodejs 中可以通过在服务器端设置代码如下实现cors跨域 res.setHeader('Access- ...
- Vue(项目踩坑)_解决vue中axios请求跨域的问题
一.前言 今天在做项目的时候发现axios不能请求跨域接口 二.主要内容 1.之前直接用get方式请求聚合数据里的接口报错如下 2.当前请求的代码 3.解决方法 (1)在项目目录中依次找到:confi ...
- django中的缓存 跨域问题(同源策略)
django缓存机制 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作 ...
- Asp.Net WebApi+Microsoft.AspNet.WebApi.Core 启用CORS跨域访问
WebApi中启用CORS跨域访问 1.安装 Nugget包Microsoft.AspNet.WebApi.Cors This package contains the components to e ...
- 解决ajax请求cors跨域问题
”已阻止跨源请求:同源策略禁止读取位于 ***** 的远程资源.(原因:CORS 头缺少 'Access-Control-Allow-Origin').“ ”已阻止跨源请求:同源策略禁止读取位于 ** ...
- 关于 Spring Security OAuth2 中 CORS 跨域问题
CORS 是一个 W3C 标准,全称是”跨域资源共享”(Cross-origin resource sharing).它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了 AJA ...
随机推荐
- 掌握 MySQL 这 19 个骚操作,效率至少提高3倍
本文我们来谈谈项目中常用的MySQL优化方法,共19条,利用好这19条方法,会让你的效率提升至少3倍. 1.EXPLAIN 做MySQL优化,我们要善用EXPLAIN查看SQL执行计划. 下面来个简单 ...
- 自学Zabbix11.2 Zabbix SNMP安装
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix11.2 Zabbix SNMP安装 1. yum安装snmp 1 # yum i ...
- 【洛谷5月月赛】玩游戏(NTT,生成函数)
[洛谷5月月赛]玩游戏(NTT,生成函数) 题面 Luogu 题解 看一下要求的是什么东西 \((a_x+b_y)^i\)的期望.期望显然是所有答案和的平均数. 所以求出所有的答案就在乘一个逆元就好了 ...
- 洛谷 P1054 等价表达式 解题报告
P1054 等价表达式 题目描述 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的 ...
- source、sh、bash
source.sh.bash../ 执行脚本的区别 1.source命令用法: source FileName 作用:在当前bash环境下读取并执行FileName中的命令.该filename文件可以 ...
- 逆向---03.mov、test等汇编指令、EAX、关键Call、OD调试技巧
上一篇:逆向---02.je & jmp & jnz .OD调试 基础知识:(栗子中也会说的)栗子:链接: https://pan.baidu.com/s/1qZbbTvQ 密码: i ...
- 【CF711D】Directed Roads
题目大意:给定一个 N 个点,N 条边的无向图,现给每条边定向,求有多少种定向方式使得定向后的有向图中无环. 题解:显然,这是一个外向树森林,定向后存在环的情况只能发生在基环树中环的位置,环分成顺时针 ...
- java中的内存空间 堆和栈
认识堆与栈 栈与堆都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆.Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过 ...
- win7(旗舰版)下,OleLoadPicture 加载内存中的图片(MagickGetImageBlob),返回值 < 0
昨天去三哥家,想把拍好的照片缩小一下,我用很久前写的一个软件进行缩小,然后进行一次效果预览,这个时候弹出: Call OleLoadPicture Fail - loadPictureFromMW 奇 ...
- Java: String.split(....); 结果很意外
String txt = "join|公共聊天室||"; String[] paras = txt.splite("\\|"); String t1 = par ...