千家信息网

MEAN怎么安装配置

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,本篇内容介绍了"MEAN怎么安装配置"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!首先定义一些小型配
千家信息网最后更新 2025年12月02日MEAN怎么安装配置

本篇内容介绍了"MEAN怎么安装配置"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

首先定义一些小型配置库。文件名:test/config/test_config.js

module.exports = {    url : 'http://localhost:8000/api/v1.0'}

服务器运行端口是 localhost 8000 ,对于初始的测试来说非常适合。之后,如果改变产品系统的位置或者端口号,只需要简单地修改这个文件就可以。为了良好地测试,首先应该建立 1 个好的测试环境,这点可以通过下面的代码保证。首先,连接到数据库。

文件名: est/setup_tests.js 。

function connectDB(callback) {    mongoClient.connect(dbConfig.testDBURL, function(err, db) {        assert.equal(null, err);        reader_test_db = db;        console.log("Connected correctly to server");        callback(0);    });}

下一步,drop user collection,这么做可以了解数据库状态。

function dropUserCollection(callback) {        console.log("dropUserCollection");        user = reader_test_db.collection('user');        if (undefined != user) {            user.drop(function(err, reply) {                console.log('user collection dropped');                callback(0);            });        } else {            callback(0);        }    },

下一步,drop user feed entry collection。

function dropUserFeedEntryCollection(callback) {    console.log("dropUserFeedEntryCollection");    user_feed_entry = reader_test_db.collection('user_feed_entry');    if (undefined != user_feed_entry) {        user_feed_entry.drop(function(err, reply) {            console.log('user_feed_entry collection dropped');            callback(0);        });    } else {        callback(0);    }}

下一步,连接到Stormpath,随后删点所有测试应用程序中的用户。

function getApplication(callback) {    console.log("getApplication");    client.getApplications({        name: SP_APP_NAME    }, function(err, applications) {        console.log(applications);        if (err) {            log("Error in getApplications");            throw err;        }        app = applications.items[0];        callback(0);    });},function deleteTestAccounts(callback) {    app.getAccounts({        email: TU_EMAIL_REGEX    }, function(err, accounts) {        if (err) throw err;        accounts.items.forEach(function deleteAccount(account) {            account.delete(function deleteError(err) {                if (err) throw err;            });        });        callback(0);    });}

下一步,关闭数据库。

function closeDB(callback) {    reader_test_db.close();}

最终,调用 async.series 来保证所有函数都按次序运行。

async.series([connectDB, dropUserCollection,    dropUserFeedEntryCollection, dropUserFeedEntryCollection, getApplication, deleteTestAccounts, closeDB]);

Frisby 在初期就被建立,这里将使用它定义测试用例,如下:

文件名:test/createaccountserror_spec.js

TU1_FN = "Test";TU1_LN = "User1";TU1_EMAIL = "testuser1@example.com";TU1_PW = "testUser123";TU_EMAIL_REGEX = 'testuser*';SP_APP_NAME = 'Reader Test';var frisby = require('frisby');var tc = require('./config/test_config');

下面代码将从 enroll route 开始。这个用例故意丢掉了 first name 字段,因此获得 1 个 400 与 1 个 JSON error(显示 first name 未定义)返回,下面就 toss that frisby:

frisby.create('POST missing firstName').post(tc.url + '/user/enroll',      { 'lastName' : TU1_LN,        'email' : TU1_EMAIL,        'password' : TU1_PW }).expectStatus(400).expectHeader('Content-Type', 'application/json; charset=utf-8').expectJSON({'error' : 'Undefined First Name'}).toss()

下面用例将测试不包含小写字母,这同样会导致 Stormpath 返回错误,以及返回400 状态。

下面将测试一个无效邮箱地址。因此,期望返回的是未发现 @ 标志,以及 emali地址缺少域名,同时也会获得 1 个 400 状态。

文件名:test/createaccountsspec.js

frisby.create('POST invalid email address').post(tc.url + '/user/enroll',      { 'firstName' : TU1_FN,        'lastName' : TU1_LN,        'email' : "invalid.email",        'password' : 'testUser' }).expectStatus(400).expectHeader('Content-Type', 'application/json; charset=utf-8').expectJSONTypes({'error' : String}).toss()

下面着眼一些可以运行的例子,首先需要定义 3 个用户。

文件名:test/createaccountsspec.js

TEST_USERS = [{'fn' : 'Test', 'ln' : 'User1',         'email' : 'testuser1@example.com', 'pwd' : 'testUser123'},          {'fn' : 'Test', 'ln' : 'User2',           'email' : 'testuser2@example.com', 'pwd' : 'testUser123'},          {'fn' : 'Test', 'ln' : 'User3',           'email' : 'testuser3@example.com', 'pwd' : 'testUser123'}]SP_APP_NAME = 'Reader Test';var frisby = require('frisby');var tc = require('./config/test_config');

下面用例将发送 1 个包含上文已定义 3 个用户的数组,当然期望获得代表成功的 201 状态。返回的 JSON document 将展示已建立的用户对象,因此这里可以检查测试数据匹配与否。

TEST_USERS.forEach(function createUser(user, index, array) {    frisby.create('POST enroll user ' + user.email)    .post(tc.url + '/user/enroll',          { 'firstName' : user.fn,            'lastName' : user.ln,            'email' : user.email,            'password' : user.pwd })    .expectStatus(201)    .expectHeader('Content-Type', 'application/json; charset=utf-8')    .expectJSON({ 'firstName' : user.fn,                  'lastName' : user.ln,                  'email' : user.email })    .toss()});

下一步将测试重复用户。下例将验证这个用户注册的 email 地址已经被使用。

frisby.create('POST enroll duplicate user ')    .post(tc.url + '/user/enroll',      { 'firstName' : TEST_USERS[0].fn,        'lastName' : TEST_USERS[0].ln,        'email' : TEST_USERS[0].email,        'password' : TEST_USERS[0].pwd }).expectStatus(400).expectHeader('Content-Type', 'application/json; charset=utf-8').expectJSON({'error' : 'Account with that email already exists.  Please choose another email.'}).toss()

这里存在一个重要问题,无法知道 Stormpath 会优先返回哪个 API key。因此,这里需要建立一个动态文件。随后可以使用这个对文件来验证测试用例--用户身份验证组件。

文件名称: /tmp/readerTestCreds.js

TEST_USERS = [{      "_id":"54ad6c3ae764de42070b27b1","email":"testuser1@example.com","firstName":"Test","lastName":"User1","sp_api_key_id":"","sp_api_key_secret":""},{       "_id":"54ad6c3be764de42070b27b2",    "email":"testuser2@example.com",    "firstName":"Test",    "lastName":"User2",    "sp_api_key_id":"",    "sp_api_key_secret":""}];module.exports = TEST_USERS;

为了建立上面这个临时文件,这里需要连接 MongoDB 从而检索用户信息。代码如下:

文件名:tests/writeCreds.js

TU_EMAIL_REGEX = new RegExp('^testuser*');SP_APP_NAME = 'Reader Test';TEST_CREDS_TMP_FILE = '/tmp/readerTestCreds.js';var async = require('async');var dbConfig = require('./config/db.js');var mongodb = require('mongodb');assert = require('assert');var mongoClient = mongodb.MongoClientvar reader_test_db = null;var users_array = null;function connectDB(callback) {    mongoClient.connect(dbConfig.testDBURL, function(err, db) {        assert.equal(null, err);        reader_test_db = db;        callback(null);    }); } function lookupUserKeys(callback) {    console.log("lookupUserKeys");    user_coll = reader_test_db.collection('user');    user_coll.find({email :    TU_EMAIL_REGEX}).toArray(function(err, users) {           users_array = users;            callback(null);    }); }function writeCreds(callback) {   var fs = require('fs');    fs.writeFileSync(TEST_CREDS_TMP_FILE, 'TEST_USERS = ');    fs.appendFileSync(TEST_CREDS_TMP_FILE,   JSON.stringify(users_array));   fs.appendFileSync(TEST_CREDS_TMP_FILE, '; module.exports =  TEST_USERS;');   callback(0); } function closeDB(callback) {   reader_test_db.close(); } async.series([connectDB, lookupUserKeys, writeCreds, closeDB]);

着眼下面代码,上文建立的临时文件在第一行就会被使用。同时,有多个 feeds 被建立,比如 Dilbert 和 the Eater Blog 。

文件名:tests/feed_spec.js

TEST_USERS = require('/tmp/readerTestCreds.js');var frisby = require('frisby');var tc = require('./config/test_config');var async = require('async');var dbConfig = require('./config/db.js');var dilbertFeedURL = 'http://feeds.feedburner.com/DilbertDailyStrip';var nycEaterFeedURL = 'http://feeds.feedburner.com/eater/nyc';

首先,一些用户会被建立,当然他们并没有订阅任何 feeds。下面代码将测试 feeds 的订阅。请注意,这里同样需要进行身份验证,通过使用 .auth 和 Stormpath API keys 完成。

function addEmptyFeedListTest(callback) {    var user = TEST_USERS[0];    frisby.create('GET empty feed list for user ' + user.email)             .get(tc.url + '/feeds')         .auth(user.sp_api_key_id, user.sp_api_key_secret)         .expectStatus(200)         .expectHeader('Content-Type', 'application/json; charset=utf-8')         .expectJSON({feeds : []})         .toss()         callback(null);}

下面用例将为第一个测试用户订阅 Dilbert feed 。

这个用例将尝试为用户 feed 重复订阅。

function subDuplicateFeed(callback) {var user = TEST_USERS[0];frisby.create('PUT Add duplicate feed sub for user ' + user.email)         .put(tc.url + '/feeds/subscribe',              {'feedURL' : dilbertFeedURL})         .auth(user.sp_api_key_id, user.sp_api_key_secret)         .expectStatus(201)         .expectHeader('Content-Type', 'application/json; charset=utf-8')         .expectJSONLength('user.subs', 1)         .toss()callback(null);}

下一步,将为测试用户添加一个新的 feed,返回的结果应该是用户当下已经订阅了 2 个 feed。

function subSecondFeed(callback) {var user = TEST_USERS[0];frisby.create('PUT Add second feed sub for user ' + user.email)         .put(tc.url + '/feeds/subscribe',              {'feedURL' : nycEaterFeedURL})         .auth(user.sp_api_key_id, user.sp_api_key_secret)         .expectStatus(201)         .expectHeader('Content-Type', 'application/json; charset=utf-8')         .expectJSONLength('user.subs', 2)         .toss()callback(null); }

下一步,将使用第 2 个测试用户来订阅 1 个 feed 。

function subOneFeedSecondUser(callback) {    var user = TEST_USERS[1];frisby.create('PUT Add one feed sub for second user ' + user.email)         .put(tc.url + '/feeds/subscribe',              {'feedURL' : nycEaterFeedURL})         .auth(user.sp_api_key_id, user.sp_api_key_secret)         .expectStatus(201)         .expectHeader('Content-Type', 'application/json; charset=utf-8')         .expectJSONLength('user.subs', 1)         .toss()callback(null);}async.series([addEmptyFeedListTest, subOneFeed, subDuplicateFeed, subSecondFeed, subOneFeedSecondUser]);

##REST API

在开始编写 REST API 代码之前,首先需要定义一些实用工具库。首先,需求定义应用程序如何连接到数据库。将这个信息写入一个独立的文件允许应用程序灵活地添加新数据库 URL,以应对开发或者生产系统。

文件名:config/db.js

如果期望打开数据库验证,这里需要将信息存入 1 个文件,如下文代码所示。出于多个原因,这个文件不应该被置入源代码控制。

文件名称:config/security.js

module.exports = { stormpath_secret_key : 'YOUR STORMPATH APPLICATION KEY';}

Stormpath API 和 Secret keys 应该被保存到属性文件,如下文代码所示,同事还需要严加注意。

文件名:config/stormpath_apikey.properties

apiKey.id = YOUR STORMPATH API KEY IDapiKey.secret = YOUR STORMPATH API KEY SECRET

##Express.js 简述

在 Express.js 中会建立应用程序(APP)。这个应用程序会监听制定的端口来响应 HTTP 请求。当请求涌入,它们会被传输到 1 个中间件链。中间件链中的每个 link 都会被给予 1 个请求和 1 个响应对象用以存储结果。link 分为两种类型,工作或者传递到下一个 link 。这里会通过 app.use() 来添加新的中间件。主中间件被称为「router(路由器)」,它会监听 URL,并将 URL/ 动作传递到 1 个指定的处理函数。 ##建立应用程序

现在开始聚焦应用程序代码,鉴于可以在独立文件中为不同的 routes 嵌入处理器,所以应用程序的体积非常小。

文件名:server.js

在 chain 中末尾定义中间件来处理坏 URLs。

现在,应用程序就会监听 8000 端口。

在控制台将消息打印给用户。

console.log('Magic happens on port ' + port);exports = module.exports = app;

##定义 Mongoose 数据模型

这里会使用 Mongoose 将 Node.js 上的对象映射成 MongoDB 文档。如上文所述,这里将建立 4 个 collections:

  • Feed collection。

  • Feed entry collection。

  • User collection。

  • User feed-entry-mapping collection。

下一步,将为 4 个 collections 定义 schema。首先,从 user schema 开始。注意,这里同样可以格式化数据,比如讲字母都转换成小写,使用 trim 消除首/末空格。

文件名:app/routes.js

var userSchema = new mongoose.Schema({         active: Boolean,     email: { type: String, trim: true, lowercase: true },     firstName: { type: String, trim: true },     lastName: { type: String, trim: true },     sp_api_key_id: { type: String, trim: true },     sp_api_key_secret: { type: String, trim: true },     subs: { type: [mongoose.Schema.Types.ObjectId], default: [] },     created: { type: Date, default: Date.now },     lastLogin: { type: Date, default: Date.now }, }, { collection: 'user' });

下面代码将告诉 Mongoose 需要哪些索引。当索引不存在于 MongoDB 数据库中时,Mongoose 将会负责索引的建立。唯一性约束保障将去除重复出现的可能。「email : 1」 将以升序的方式维护地址,而「email : -1」则是降序。

在其他 3 个 collections 上重复这个步骤。

var UserModel = mongoose.model( 'User', userSchema );var feedSchema = new mongoose.Schema({     feedURL: { type: String, trim:true },     link: { type: String, trim:true },     description: { type: String, trim:true },     state: { type: String, trim:true, lowercase:true, default: 'new' },     createdDate: { type: Date, default: Date.now },     modifiedDate: { type: Date, default: Date.now }, }, { collection: 'feed' });feedSchema.index({feedURL : 1}, {unique:true});feedSchema.index({link : 1}, {unique:true, sparse:true});var FeedModel = mongoose.model( 'Feed', feedSchema );var feedEntrySchema = new mongoose.Schema({     description: { type: String, trim:true },     title: { type: String, trim:true },     summary: { type: String, trim:true },     entryID: { type: String, trim:true },     publishedDate: { type: Date },     link: { type: String, trim:true  },     feedID: { type: mongoose.Schema.Types.ObjectId },     state: { type: String, trim:true, lowercase:true, default: 'new' },     created: { type: Date, default: Date.now }, }, { collection: 'feedEntry' });feedEntrySchema.index({entryID : 1});feedEntrySchema.index({feedID : 1});var FeedEntryModel = mongoose.model( 'FeedEntry', feedEntrySchema     );var userFeedEntrySchema = new mongoose.Schema({     userID: { type: mongoose.Schema.Types.ObjectId },     feedEntryID: { type: mongoose.Schema.Types.ObjectId },     feedID: { type: mongoose.Schema.Types.ObjectId },     read : { type: Boolean, default: false }, }, { collection: 'userFeedEntry' } );

下面是复合索引实例,每个索引都以升序维护。

userFeedEntrySchema.index({userID : 1, feedID : 1, feedEntryID : 1, read : 1});var UserFeedEntryModel = mongoose.model('UserFeedEntry', userFeedEntrySchema );

每个用于 GET、POST、PUT 和 DELETE 的请求需要拥有 1 个正确的内容类型,也就是 application/json。然后下一个 link 会被调用。

下一步需要为每个 URL/verb 定义处理器。参考资料部分附上了所有代码,下面只是代码片段。在这些代码中,Stormpath 带来的便捷一览无余。此外,这里定义的是 /api/v1.0 ,举个例子,这里客户端可以调用的是 /api/v1.0/user/enroll。如果使用 /api/v2.0,/api/v2.0 则可以被使用,当然向下兼容。

要启动服务器和运行测试,这里需要遵循几个步骤。

  1. 保证 MongoDB 实例运行,mongod。

  2. 安装 Node 库,npm install。

  3. 开启 REST API 服务器,node server.js。

  4. 运行测试用例:node setup_tests.js;jasmine-node create_accounts_error_spec.js;jasmine-node create_accounts_spec.js;node write_creds.js;jasmine-node feed_spec.js

"MEAN怎么安装配置"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

文件 测试 用户 代码 文件名 数据 应用程序 程序 应用 数据库 订阅 运行 中间件 索引 验证 地址 状态 处理 配置 信息 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海专业性网络技术活动方案 加强网络安全 推进信息 开源服务器运维管理系统 网页无法访问oracle数据库 网络安全法谈个人信息 linux服务器挂载阿里云盘 有线网络比无线网络安全 暴雪服务器过载无法连接 不同数据库的表如何关联查询 一个软件开发成网页和app 最新网络技术应用前沿 软件开发者怎么在云端开发 网络安全职业发展前景 wingy服务器 为什么服务器需要很多核心 中小学生教育5网络安全 服务器市场报告 x86 合肥二手服务器回收在线咨询 股票软件开发 合肥 c乥f网络安全大赛 c 实现数据库连接 车路协同网络技术 广东软件开发能赚多少钱 软件开发服务公司经营范围 监狱网络安全管理体检要求 视频服务器如何与笔记本电脑连接 网络技术书六单元习题 搭建小说网站需要多大的服务器 怎么检查服务器的问题 服务器如何接通网络
0