使用Ionic(AngularJS框架)与MongoDB建立连接
简述
使用Ionic进行开发时,我读取了一个假的Json文件并显示了其中的数据,但是我意识到必须正确地连接到数据库,于是我决定在本地搭建MongoDB并记录连接的过程。
另外,由于最终计划是将与AWS的DynamoDB连接的请求嵌入到Angular的Controller中,所以Node.js->MongoDB只是用于测试目的而构建。
前提 tí)
下面是开发环境。
-
- OS: Mac OS X El Capitan
-
- Angular: 1.X系
-
- Cordova CLI: 6.0.0
-
- Gulp version: CLI version 3.9.1
-
- Ionic Version: 1.2.4
-
- Ionic CLI Version: 1.7.14
-
- Ionic App Lib Version: 0.7.0
-
- Node Version: v5.5.0
- MongoDB shell version: 3.2.5
Angular是否可以与MongoDB一起使用?
最初我搜索了关于能否连接前端的Angular和Mongo的问题。根据J2EE的思路,我认为可以直接从Servlet(Web容器)连接到DAO层进行调查,但结果看起来确实有些困难(当然,在运行Ionic时使用的服务器似乎是Node.js,所以可能是可行的。但是,我对此的印象是由于有许多考虑事项而变得非常麻烦)
所以,我们转向了替代方案。
Ionic(Angular) -> Node -> MongoDB
Ionic(Angular)在Node上连接MongoDB。
我本能地尝试着在两者之间加入一个Node服务器进行通信,希望能成功。
var express = require('express'),
mongodb = require('mongodb');
var app = express();
app.set('port', process.env.PORT || 3000);
// 私の環境ではMongoのポートである{ポート番号}=27017
// Nodeサーバのポート番号は3000としています
mongodb.MongoClient.connect("mongodb://localhost:{ポート番号}/{DB名称}", function(err, database) {
tmp = database.collection("{コレクション名称}");
});
// Acquiring the list of goods we bought
app.get("/api/tmp", function(req, res) {
tmp.find().toArray(function(err, items) {
res.send(items);
});
});
// サーバ起動
http.createServer(app).listen(app.get('port'), function() {
console.log('Node.js with Express server listening on port ' + app.get('port'));
});
执行app.js。
$ node app.js
Node.js使用Express服务器在3000端口监听。
由于内部结构简单,服务器可以轻松启动。
执行离子端。
接下来,我们将按照以下方式对ionic进行编码。
var url = 'http://localhost:3000/api/tmp';
$scope.tmplist = [];
$http.get(url).success(function(data, status) {
// set json data acquired from DB
console.info(status, data);
$scope.tmpList = data;
}).error(function(data, status) {
// if cannot get data from DB, set local json data to goodsList
console.error(status, data);
});
我也会启动Ionic。然后在隐私模式下启动Chrome,并同时启动开发人员工具进行确认。
使用Ionic命令在iOS设备上进行本地测试—>ionic 本地测试 iOS 设备
从浏览器确认!
(浏览器搜索)http://localhost:8100/ -> (浏览器搜索)http://localhost:8100/
当时出现错误,无法正常运行。。。查看谷歌浏览器的控制台后发现以下错误。
XMLHttpRequest无法加载http://localhost:3000/api/tmp。请求的资源未包含’Access-Control-Allow-Origin’标头。因此,不允许访问来自http://localhost:8100的请求源。
跨域资源共享(CORS)吗?确实,当使用MEAN堆栈构建应用程序时,通常不需要担心Node和Angular是否在同一域上。因为我使用Angular进行编写,所以没有意识到这一点,但是由于Node服务器和ionic服务器位于不同域上,所以需要考虑这个问题。
(*1) CORS:跨源资源共享的缩写。它是浏览器从加载HTML的服务器之外的服务器获取数据的机制。一般的浏览器已经实现了通过XSS防止跨域通信的机制。
用JSONP来处理一下
可以添加一个不使用CORS的标头,但是由于不同域的JSON数据获取通常使用JSONP请求,我们可以尝试将GET请求改为JSONP请求进行提交。
以下是一个本地化的中文翻译(仅提供一个选项):
<参考>
https://docs.angularjs.org/api/ng/service/$http#jsonp
http://qiita.com/izumin5210/items/e6e529d61c4d246f87fb
以上链接提供了有关AngularJS中的”$http”服务和”jsonp”方法的相关信息。
var url = 'http://localhost:3000/api/tmp?callback=JSON_CALLBACK';
$scope.tmplist = [];
$http.jsonp(url).success(function(data, status) {
// set json data acquired from DB
console.info(status, data);
$scope.tmpList = data;
}).error(function(data, status) {
// if cannot get data from DB, set local json data to goodsList
console.error(status, data);
});
再次使用ionic从Chrome访问!!…嗯?不起作用…
对了,还是有CORS问题。
*即使从浏览器访问目标url1(http://localhost:3000/api/tmp),可以正确获取JSON格式的数据。
尽管我尝试过各种方法来研究JSONP的用法,并在app.js中明确设置返回JSON的形式,但没有任何变化,所以我决定转到下一个策略。
在HTTP响应中加入Access-Control标头
试着根据《在Express上使用CORS》这篇文章中的参考方式进行集成。
var express = require('express'),
mongodb = require('mongodb');
var app = express();
app.set('port', process.env.PORT || 3000);
app.use(function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
});
・・・省略・・・
// Acquiring the list of goods we bought
app.get("/api/tmp", function(req, res) {
tmp.find().toArray(function(err, items) {
res.send(items);
});
});
提升节点服务器,执行ionic命令并确认结果,CORS问题已经消失了,但是仍然没有收到任何HTTP响应,无法进行屏幕渲染。根据下面的指示,尝试将其明确地嵌入头部,问题得到了解决。
var express = require('express'),
mongodb = require('mongodb');
var app = express();
app.set('port', process.env.PORT || 3000);
・・・省略・・・
// Acquiring the list of goods we bought
app.get("/api/tmp", function(req, res) {
tmp.find().toArray(function(err, items) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.send(items);
});
});
因为这种方法需要在每个请求中都加入CORS绕过头部,所以我觉得不是很好,但是因为其他方法都不起作用,所以只能放弃了。
目前,我成功地使用Ionic实现了与MongoDB的通信,感到非常满意。
此外,当使用DynamoDB时,请将http.get的url设置为AWS API Gateway或Lambda的URL即可。不再需要在Node.js的app.js中编写跨源资源共享(CORS)的头部信息。