解决 ionic 中的 CORS(跨域)

译者注:本人翻译功力有限,因此文中不免有翻译不许确的地方,凑合看吧,牛逼的话你看英文版的去,完事儿欢迎回来指正交流(^_^)html

若是你经过 ionic serve 或者 ionic run 命令使用或 live reload 或者访问过外部 API 结点,那么你确定遇到过 CORS 问题,譬以下面这样:git

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 呢?又是什么致使了这个问题嘞?github

什么是 CORS?

CORS=Cross origin resource sharing(跨域资源共享)web

origin 就是你如今正在看的主站,你如今访问的是 http://ionicframework.com/blog/handling-cors-issues-in-ionic,那么 origin 就是 ionicframework.comnpm

若是说咱们向 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.comapi.com 的主机并不匹配,因此在一个HTTP OPTIONS请求报头的 form 中咱们全部从 ionicframework.com 发起的访问服务器资源的请求必修获得服务器的受权。gulp

假如上面的请求出现错误(不被服务器容许),那么咱们是没法从服务器访问到(api.com上的)资源的。api

让咱们来看一下当你经过ionic serveionic runionic 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 serveionic run -l 运行应用才须要

首先咱们须要在 ionic.project文件中设置咱们的代理,这会告诉咱们的 Ionic 本地服务器监听这些地址,而后发送这些请求到咱们的目标地址上。

在咱们的应用中,当运行 serverun -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 serveionic run -l命令运行应用时候遇到的 CORS 问题的方法。

咱们知道在ionic serveionic run -l之间转换 API 结点地址的时候可能会是个麻烦,比较建议的方法是启动一个 gulp 进程。

解决 CORS 问题最简单的方法是让 API 提供者容许全部的 hosts,而后这事儿有点儿不太现实。

使用 Angular constant 和 replace 模块能够给咱们一个避开 CORS 的折中的办法。

若是你想看看完整的例子,能够看看这个示例项目

这就是你须要访问一个有 CORS 限制的 API 服务器时候须要了解的全部事儿了。

若是你还有什么疑问、问题或者想法,请在下面评论,或者在 twittergithub 上联系咱们。

相关文章
相关标签/搜索