个多如牛毛错误,项目实战

NodeJS 开辟者的 10 个平淡无奇错误

2015/06/16 · CSS · 1 评论

本文由 伯乐在线 - 刘健超-J.c 翻译,黄利民 校稿。未经许可,禁止转发!
匈牙利(Hungary卡塔 尔(英语:State of Qatar)语出处:www.toptal.com。迎接出席翻译组。

自 Node.js 公之世人的那一刻,就伴随着陈赞和研究的鸣响。这么些争辨仍在持续,並且并不会神速破灭。而作者辈日常忽视掉那些纠纷发生的因由,各类编制程序语言和平台都是因一些难题而饱受批评,而这么些难点的发出,是决意于大家如何行使这些平台。不管有多难工夫写出安全的 Node.js 代码,或有多轻松写出高并发的代码,该平台早就有非常短黄金年代段时间,并已被用来创建三个数目宏大、稳健和老成的 web 服务器。那一个 web 服务器伸缩性强,并且它们经过在 Internet 上稳定的周转时刻,表明本身的安静。

然而,像别的平台同样,Node.js 轻易因开辟者难题而碰到商议。一些不当会骤降品质,而其余一些难点会让 Node.js 直接崩溃。在这里篇作品里,大家将会聊风姿罗曼蒂克聊关于 Node.js 新手的 十一个常犯错误,并让他俩掌握哪些防止这个错误,进而成为一名 Node.js 高手。

图片 1

本章首要讲哪些(一句话卡塔尔国?

本章主要教授:利用mongoose第三方库实行业务数据操作

图片 2

                                                  --  

#  Node.js学习笔记

 1、早先应用mongoose时,得先安装,展开命令行,实行$ npm install mongoose

错误 #1:堵塞事件循环

JavaScript 在 Node.js (就好像在浏览器相像) 提供单线程实施景况。那表示你的主次不可能同时实践两有的代码,但能透过 I/O 绑定异步回调函数实现产出。举例:二个来源Node.js 的伸手是到数据库引擎获取一些文档,在此同期同意 Node.js 专心于应用程序其余一些:

JavaScript

// Trying to fetch an user object from the database. Node.js is free to run other parts of the code from the moment this function is invoked.. // 尝试从数据库中获取三个顾客对象。在这里个函数推行的说话,Node.js 有空去运作代码此外一些.. db.User.get(userId, function(err, user) { // .. until the moment the user object has been retrieved here // .. 直到客户对象检索到此处的那一刻 })

1
2
3
4
5
6
// Trying to fetch an user object from the database. Node.js is free to run other parts of the code from the moment this function is invoked..
// 尝试从数据库中获取一个用户对象。在这个函数执行的一刻,Node.js 有空去运行代码其它部分..
db.User.get(userId, function(err, user) {
// .. until the moment the user object has been retrieved here
        // .. 直到用户对象检索到这里的那一刻
})

图片 3

但是,具备总计密集型代码的 Node.js 实例被生机勃勃体系顾客端同时连接实施时,会变成短路事件循环,并使具备顾客端处于等候响应状态。总括密集型代码,满含尝试给二个硕大数组实行排序操作和平运动作二个比极短的巡回等。举例:

JavaScript

function sortUsersByAge(users) { users.sort(function(a, b) { return a.age > b.age ? -1 : 1 }) }

1
2
3
4
5
function sortUsersByAge(users) {
users.sort(function(a, b) {
return a.age > b.age ? -1 : 1
})
}

基于小 “users” 数组推行 “sortUserByAge” 函数,可能没什么难点,当基于宏大数组时,会严重影响全部品质。如若在不能不如此操作的场合下,你必需保险程序除了等候事件循环而别无他事(比如,用 Node.js 创设命令行工具的风流倜傥有个别,整个东西一块运维是没难点的卡塔 尔(英语:State of Qatar),然后这只怕没难点。然则,在 Node.js 服务器实例尝试同有时间服务广大个客户的情形下,那将是多个灭亡性的题材。

假诺客商数组是从数据库检索出来的,有个消除办法是,先在数据库中排序,然后再平昔找出。若是因急需总结庞大的金融交易历史数据总和,而导致堵塞事件循环,那足以创制额外的worker / queue 来防止梗塞事件循环。

正如你所看见的,那并未有新技术来解决那类 Node.js 难题,而每一个状态都急需单独管理。而基本消除思路是:不要让 Node.js 实例的主线程实行 CPU 密集型专业 – 顾客端同一时候链接时。

一、前言

上大器晚成章重视对品种引进MongoDB进行数据存款和储蓄,并导入mongoose第三方组件,达成mongodb数据库配置及连接代码,本节继续。

## 简介

- 编写高质量互联网服务器的JavaScript工具包

- 单线程、异步、事件驱动

- 特点:快,耗内部存款和储蓄器多

- PHP是单线程,耗内部存款和储蓄器少速度相对慢些

2、连接mongodb数据库,在app.js里面增加如下两行代码。

错误 #2:调用回调函数多于壹回

JavaScript 一贯都是依靠于回调函数。在浏览器中,处监护人件是通过调用函数(平日是无名氏的卡塔 尔(英语:State of Qatar),那些动作就像是回调函数。Node.js 在引入 promises 在此以前,回调函数是异步成分用来互相连接对方的无出其右办法 。现在回调函数仍被利用,并且包开拓者还是围绕着回调函数设计 APIs。三个关于利用回调函数的管见所及 Node.js 问题是:不仅贰遍调用。平时状态下,一个包提供贰个函数去异步管理部分事物,设计出来是期待有一个函数作为最后三个参数,当异步义务到位时就能够被调用:

JavaScript

module.exports.verifyPassword = function(user, password, done) { if(typeof password !== ‘string’) { done(new Error(‘password should be a string’)) return } computeHash(password, user.passwordHashOpts, function(err, hash) { if(err) { done(err) return } done(null, hash === user.passwordHash) }) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports.verifyPassword = function(user, password, done) {
if(typeof password !== ‘string’) {
done(new Error(‘password should be a string’))
return
}
 
computeHash(password, user.passwordHashOpts, function(err, hash) {
if(err) {
done(err)
return
}
 
done(null, hash === user.passwordHash)
})
}

小心每趟调用 “done” 都有一个回去语句(return卡塔尔,而最终叁个 “done” 则可省略再次回到语句。那是因为调用回调函数后,并不会自动终止近来进行函数。尽管第多少个“return” 注释掉,然后给这几个函数传进一个非字符串密码,导致 “computeHash” 如故会被调用。那取决 “computeHash” 如哪个地方理那样风流倜傥种意况,“done” 恐怕会调用数次。任何一人在别处使用那么些函数只怕会变得措手不比,因为它们传进的该回调函数被一再调用。

只要当心就能够幸免这一个 Node.js 错误。而有个别 Node.js 开荒者养成一个习于旧贯是:在各类回调函数调用前增多一个 return 关键字。

JavaScript

if(err) { return done(err) }

1
2
3
if(err) {
return done(err)
}

对于广大异步函数,它的再次回到值大致是空虚的,所以该方法能令你很好地防止这几个标题。

二、本事关健词

Node、MongoDB、Angular2、mongoose

## 在Linux上安装node

  1. 先安装二个[nvm](:

- 进入nvm的GitHub点击README的installation

- 找到下列代码(为了获得最新的版本卡塔尔国复制下  来输入到Ubuntu的指令行中

```bash

curl -o- | bash

```

- 安装完要重启一下

- 激活nvm

```bash

echo ". ~/.nvm/nvm.sh" >> /etc/profile

source /etc/profile

```

- 输入nvm测量检验,如若报错:

```bash

Computing checksum with shasum -a 256 Checksums do not match:

```

- 就再输入:

```bash

export NVM_DIR="$HOME/.nvm"

#相当就再输入

. "/usr/local/opt/nvm/nvm.sh"

```

- 假设还报错去[官网](

  1. nvm安装完成后输入:

```bash

nvm install --lts

nvm use (你安装的版本号)

```

- 安装新型牢固版,并选择它

- 输入node,如若步向了node交互蒙受就设置成功了

- 纵然要查看已经安装的node版本,输入:

```bash

nvm ls

```

  1. 一应俱全安装

- 上述进度完毕后,不时汇合世,当张开叁个新的 shell 窗口时,找不到 node 命令的图景,这种场地相符来自多个原因:

- 一、shell 不知道 nvm 的存在

- 二、nvm 已经存在,不过尚未 default 的 Node.js 版本可用。

- 消除方法:

- 一、检查 ~/.profile 或者 ~/.bash_profile 中有未有如此两句

```bash

export NVM_DIR="/Users/YOURUSERNAME/.nvm"

[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm

```

- 没有的话,加进去。这两句会在 bash 运行的时候被调用,然后注册 nvm 命令。

- 二、调用

```bash

nvm ls

```

- 看看有未有 default 的指向性。若无的话,推行

```bash

$ nvm alias default (你安装的版本号)

#再

$ nvm ls

#看一下

```

## 基本HTTP服务器

```javascript

//server.js

var http = require('http');                    //导入Node.js自带的HTTP模块

http.createServer(function(request,response){  //调用HTTP模块的createServer()函数成立二个服务,该函数有四个参数:request和response它们是指标,用它们的艺术来拍卖HTTP诉求的细节,况兼响应必要

    response.statusCode = 200;                  //再次回到的状态码

    response.setHeader('Content-Type', 'text/plain');  //HTTP合同头出口类型

    response.end();                            //甘休HTTP诉求,不写就未有HTTP左券尾

}).listen(8000);                                //监听8000端口

console.log("Server running at ")

```

- createServer()方法接纳四个办法作为参数

- 若是只是上边的二个粗略劳动,浏览器访谈时会提交五遍HTTP恳求(express框架中曾经消弭)

- 即使不用express框架,需手工业灭亡:

```javascript

if(request.url !== "/favicon.ico"){    //歼灭第2次访谈:因为多数浏览器都会在你拜谒 时尝试读取

    response.write();

    response.end();

}

```

## 调用其余函数

### 调用本文件内的函数

```javascript

//server.js

var http = require('http');

http.createServer(function(request,response){

    response.statusCode = 200;

    response.setHeader('Content-Type', 'text/plain');

    test(response);    //直接调用

    response.end();

}).listen(8000);

console.log("Server running at ");

function test(res){

    res.write("hello world!")

}

```

### 调用别样文件内的函数

- 原文件

```javascript

//server.js

var http = require('http');

var test = require('./test.js')

http.createServer(function(request,response){

    response.statusCode = 200;

    response.setHeader('Content-Type', 'text/plain');

    //调用艺术1:

    test.hello(response);

    test.world(response);

    //方式2:

    test['hello'](response);

    test['world'](response);

    //方法2更为常用,因为能够由此:

    var funname = 'hello';

    test[funname](response)

    //这种方式,退换字符串(funname)进而调用想要的函数

    response.end();

}).listen(8000);

console.log("Server running at ");

```

- 要调用的文书

```javascript

//test.js

//形式1:

function hello(res){

    res.write("hello");

};

function world(res){

    res.write("world");

};

module.exports = hello;    //只帮衬叁个函数

//形式2:扶植多少个函数

module.exports = {

    hello: function(res){

        res.write("hello");

    },

    world: function(res){

        res.write("world");

    }

}

```

- 唯有用module.exports导出,此文件内的办法才干被别的文件调用

## 模块的调用

- JavaScript中类的写法:

```javascript

//user.js

function user (id,name,age){

    this.id=id;

    this.name=name;

    this.age=age;

    this.self=function(){

        console.log(this.name "is" this.age "years old");

    }

}

module.exports = user;

```

- 调用

```javascript

//server.js

var http = require('http');

个多如牛毛错误,项目实战。var user = require('./user')

http.createServer(function(request,response){

    response.statusCode = 200;

    response.setHeader('Content-Type', 'text/plain');

    user1 = new user(1,"Rain",20);

    user1.self();

    response.end();

}).listen(8000);

console.log("Server running at ");

```

- ps: JavaScript中类的接轨:

```javascript

var user = require('./user');

function admin (id,name,age){

    user.apply(this,[id,name,age]);

    this.idis=function(res){

        res.write(this.name "is the" this.id "th");

    }

}

module.exports = admin;

```

## 路由

- 通过剖析url获取路由的字符串,调用路由文件内相应的办法,通过该办法读取对应的HTML文件,再将HTML文件重临给客商端

```javascript

//server.js

var http = require('http');

var url = require('url');          //node.js提供一个“url”对象来剖判url

var router = require('./router');  //引入路由文件

http.createServer(function(request,response){

    response.statusCode = 200;

    response.setHeader('Content-Type', 'text/plain');

    var pathname = url.parse(request.url).pathname;    //通过url.pathname方法深入分析出url前边的路由

    pathname = pathname.replace(///,'')                //通过正则将路由字符串的斜杠头给去掉

    router[pathname](request,response);                //通过pathname字符串调用路由中对应的办法

    response.end();

}).listen(8000);

console.log("Server running at ");

```

- 路由文件:router.js

```javascript

//router.js

module.exports={

    login: function(req,res){

        res.write("转到login页面")

    }

    register: function(req,res){

        res.write("转到注册页面")

    }

}

```

## 读取文件

### 同步读取文件(不引入卡塔尔国

- 读取文件的布局文件:optfile.js

```javascript

//optfile.js

var fs = require('fs');                //node.js提供的操作文件模块

module.exports={

    readfileSync: function (path) {    //同步读取方法

        var data = fs.readFilesSync(path,'utf-8');  //通过fs的readFilesSync方法同步读取文件,path为文件路线,以utf-8的编码读取

        return data;

    },

    readfile: function (path) {        //异步读取方法

        fs.readFile(path,function(err,data){

            if (err){

                console.log(err);

            } else {

                return data

            };

            console.log("函数施行完结");

        });

    }

}

```

```javascript

//server.js

var http = require('http');

var optfile = require('./optfile.js');  //引进配置文件

http.createServer(function(request,response){

    response.statusCode = 200;

    response.setHeader('Content-Type', 'text/plain');

    optfile.readfileSunc('.src/login.html')  //路线是相对于此文件的

    response.end("主程序执行完结");

}).listen(8000);

console.log("Server running at ");

```

- node.js的高品质重要就是依附异步操作,在异步时,当服务器施行读文件的操作时前后相继会继续实施下去,而不是在原地等公事读取完成,由此上述代码会在调控台依次输出:

```bash

函数实施实现

主程序实施实现        #文件还未有读取完主程序就曾经竣事了(response.end)

(最终回到读取到的公文内容“data”卡塔 尔(英语:State of Qatar)

```

- 而便是出于这种异步操作,假如想要将读取的文件内容重临给客商端,将要接纳“闭包”的点子

```javascript

//server.js

var http = require('http');

var optfile = require('./optfile.js');  //引进配置文件

http.createServer(function(request,response){

    response.statusCode = 200;

    response.setHeader('Content-Type', 'text/plain');

    function recall(data){              //创立闭包函数

        response.write(data);          //它能够储存response

        response.end();

    }

    optfile.readfileSunc('.src/login.html',recall)  //路线是对峙于此文件的

}).listen(8000);

console.log("Server running at ");

```

```javascript

//optfile.js

var fs = require('fs');

module.exports={

    readfileSync: function (path) {    //同步读取方法

        var data = fs.readFilesSync(path,'utf-8');

        return data;

    },

    readfile: function (path,recall) {        //异步读取方法,接入闭包函数

        fs.readFile(path,function(err,data){

            if (err){

                console.log(err);

            } else {

                recall(data);                  //因为是闭包函数recall会积存response

            };

            console.log("函数实施完结");

        });

    }

}

```

## 写文件

- 在optfile.js中步入写文件作用:

```javascript

//optfile.js

var fs = require('fs');

module.exports = {

    writefile: function (path,recall) {

        fs.readFile(path, function(err,data){      //异步格局

            if(err){

                console.log(err)

            } else {

                console.log("It's saved!");        //文件被封存

                recall("写入文件成功");

            }

        })

    }

}

```

- 在server.js中加入:

```javascript

optfile.writefile("./src/data.json","这里传出想要写入的数据",recall);

```

- PS:实际支出进程中,那几个函数日常是不放在server.js中的,应该放在路由配置文件中,配置相应的写多少接口

## 读取并出示图片

- 在optfile.js中投入写文件作用:

```javascript

readImg: function(path,res){

    fs.readFile(path,"binary",function(err,filedata){  //binary参数代表读取的是一个二进制流的文件

        if(err){

            console.log(err);

            return;

        } else {

            res.write(filedata,"binary");              //用“binary”的格式发送数据

            res.end();

        }

    })

}

```

- 这种办法只好独立读取图片

## 参数选取

- 只需纠正路由文件中的:

```javascript

var querystring = require('querystring');      //需求引进querystring模块来剖析POST央求体中的参数

confirm: function (req,res) {

    //get方式抽出参数,管理是联合的

    var rdata = url.parse(req.url,true).query;

    if(rdata['email'] != undefined){

        console.log("email:" rdata['email'] "," "password:" rdata['password']);

    };

    //post方式选用参数,管理是异步的

    var post = '';

    req.on('data',function(chunk){

        post = chunk;

    });

    req.on('end',function(){

        post = querystring.parse(post);

        console.log(post['email'] "," post['password']);

    });

}

```

## 动态数据渲染

- 在接收路由传输文件的时候假若想要将页面中或多或少字段动态的替换到对应的数码,能够在数据(data)传输时先将其字符化(toString()),再利用正则将同盟到的标志字符举办沟通,如vue中就利用"{{}}"双大括号标志数据地方,再开展般配替换为相应数据

- 如校勘回调函数

```javascript

function recall(data){

    dataStr = data.toString();

    for(let i=0;i

        re = new RegExp("{" arr[i] "}",g);  //用正则匹配标记数据(这里笔者用“{}”多个大括号标记数据卡塔尔

        dataStr = dataStr.replace(re,post[arr[i]])  //从数据库中循环替换对应的多少

    }

    res.write(dataStr);

    res.end();

}

```

## 异步流程序调节制

- 当有几许操作须求依靠于上一步操作实现后手艺执行,因为node里的操作大都是异步的,那就需求对异步流程打开调节

- node.js提供了五个异步流程序调整制指标async

  1. 串行非亲非故乎:async.series  (依次实践,此步实践的结果不影响下一个顺序)

  2. 相互非亲非故乎:async.parallel (相同的时间推行,寻常的异步)

  3. 串行有涉及:waterfall  (瀑布流)

- async需求其余安装:

```bash

npm install async --save-dev

```

## 连接MySQL数据库

### 直接连接(一时用,需询问卡塔 尔(英语:State of Qatar)

- 安装MySQL支持:

```bash

npm install mysql

```

- 成立叁个新的数据库,建表:

```mysql

create table user(

    uid int not null primary key auto_increment,    //id自增长

    uname varchar(100) not null,

    pwd varchar(100) not null

)ENGINE=InnoDB DEFAULT CHARSET=utf8;

```

- 间接连接MySQL并展开操作,下边列举了生机勃勃部分常用的操作,在实操进程中貌似把那几个操作封装到相应的方式中,要求的时候平昔调用

```javascript

var mysql = require("mysql")    //调用MySQL模块

//创设一个connection

var connection = mysql.createConnection({

    host: 'localhost',  //主机

    user: 'root',      //MySQL认证客户名

    password: "",      //MySQL认证客商密码

    database: "rain",  //数据库名

    port: '3306'        //端口号

});

//打开connection连接

connection.connect(function(err){

    if(err){

        console.log('[query] - :' err);

        return;

    }

    console.log("[connection connect] succeed");

})

//向表中插入数据

var userAddSql = "insert into user (uname,pwd) values(?,?)";    //要实践的MySQL语句,value的问号是占位符

var param = ['test','test'];                                    //要插入的数量可以通过变量传值,这里用字符串测验

connection.query(userAddSql,param,function(err,rs){            //调用query方法插入数据,第叁个参数是施行的MySQL语句,第四个是插入的数目,第2个是佚名回调函数管理报错;传的值应当要和MySQL语句相称

    if(err){

        console.log("insert err:",err.message);

        return;

    }

    console.log(rs);    //rs是插入成功后回去的有的参数

});

//实行查询

//群众体育查询

connection.query('SELECT * from user',function(err,rs,fields){

    if(err){

        console.log('[query] - :' err);

        return;

    }

    for(let i=0;i

        console.log('The solution is: ',rs[i].uname);

    }

    console.log(田野s);        //田野(field)s为查询发生的音信,不是查询结果,平常没什么用

})

//单独查询

connection.query('SELECT * from user where uid=?',[2],function(err,rs,田野(field)s){  //查询uid=2的那条数据

    if(err){

        console.log('[query] - :' err);

        return;

    }

    for(let i=0;i

        console.log('The solution is: ',rs[i].uname);

    }

    console.log(fields);

})

//关闭connection连接

connection.end(function(err){

    if(err){

        console.log(err.toString());

        return;

    }

    console.log("[connection end] succeed");

})

```

- 这里列举的操作都以较为常用的,还会有其余的操作能够直接通过改换传入的MySQL语句来产生

### 连接池连MySQL(常用,功能高卡塔 尔(阿拉伯语:قطر‎

- 原理:

- 创设MySQL连接的花费拾分了不起

- 使用连接池 server运转时会创造10-十多个一而再延续放在连接池中,当有访谈需三番五次MySQL数据库时,就从连接池中抽出叁个连连,实行数据库操作,操作达成后,再将接连放回连接池

- 连接池会自动的管理总是,当连接比较少时,会压缩连接池中的连接,当连接量一点都不小时,会扩明斯克接

- 使用node提供的总是池需安装node-mysql模块:

```bash

npm install node-mysql -g

```

#### 操作连接池

```javascript

//optPool.js

var mysql = require('mysql');

function optPool(){        //创造叁个连接池的类方便使用

    this.flag = true;      //用来标识是或不是连接过

    this.pool = mysql.createPool({

        host: 'localhost',  //主机

        user: 'root',      //MySQL认证顾客名

        password: "",      //MySQL认证客户密码

        database: "rain",  //数据库名

        port: '3306'        //端口号

    });

    this.getPool = function(){  //初始化pool

        if(this.flag){

            //监听connection事件

            this.pool.on('connection',function(connection){

                connection.query('SET SESSION auto_increment_increment=1');

                this.flag = false;

            });

        }

        return this.pool;

    }

};

module.exports = optPool;  //导出为一个类

```

```javascript

var optPool = require('./optPool');

var optpool = new optPool();

var pool = optpool.getPool();

//从连接池中获得二个一而再

pool.getConnection(function(err,connect){  //要是操作成功就获得连年(connect卡塔尔国

    //做三个布署操作

    var userAddSql = "insert into user (uname,pwd) values(?,?)";

    var param = ['test','test'];

    connect.query(userAddSql,param,function(err,rs){    //异步操作

        if(err){

            console.log("insert err:",err.message);

            return;

        }

        console.log('success');

        connect.release()  //将连接放回连接池

    });

})

```

[javascript]
var mongoose = require('mongoose'); 
mongoose.connect('mongodb://localhost/test'); //连接到多个test的数目库 

错误 #3:函数嵌套过深

函数嵌套过深,时常被叫作“回调函数鬼世界”,但那并不是 Node.js 自己难点。不过,那会诱致二个主题素材:代码比很快失去调整。

JavaScript

function handleLogin(..., done) { db.User.get(..., function(..., user) { if(!user) { return done(null, ‘failed to log in’) } utils.verifyPassword(..., function(..., okay) { if(okay) { return done(null, ‘failed to log in’) } session.login(..., function() { done(null, ‘logged in’) }) }) }) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function handleLogin(..., done) {
db.User.get(..., function(..., user) {
if(!user) {
return done(null, ‘failed to log in’)
}
utils.verifyPassword(..., function(..., okay) {
if(okay) {
return done(null, ‘failed to log in’)
}
session.login(..., function() {
done(null, ‘logged in’)
})
})
})
}

图片 4

职分有多复杂,代码就有多不佳。以这种方法嵌套回调函数,我们比较轻易就能够境遇难点而咽气,而且难以阅读和保卫安全代码。生龙活虎种取代方式是以函数注明那么些职务,然后将它们连接起来。尽管,有豆蔻梢头种最绝望的点子之风流浪漫(有顶牛的卡塔尔是应用 Node.js 工具包,它非常管理异步 JavaScript 格局,例如 Async.js :

JavaScript

function handleLogin(done) { async.waterfall([ function(done) { db.User.get(..., done) }, function(user, done) { if(!user) { return done(null, ‘failed to log in’) } utils.verifyPassword(..., function(..., okay) { done(null, user, okay) }) }, function(user, okay, done) { if(okay) { return done(null, ‘failed to log in’) } session.login(..., function() { done(null, ‘logged in’) }) } ], function() { // ... }) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function handleLogin(done) {
async.waterfall([
function(done) {
db.User.get(..., done)
},
function(user, done) {
if(!user) {
return done(null, ‘failed to log in’)
}
utils.verifyPassword(..., function(..., okay) {
done(null, user, okay)
})
},
function(user, okay, done) {
if(okay) {
return done(null, ‘failed to log in’)
}
session.login(..., function() {
done(null, ‘logged in’)
})
}
], function() {
// ...
})
}

就疑似于 “async.waterfall”,Async.js 提供了过多其余函数来缓和差别的异步形式。为了简洁,大家在这里处运用一个较为简单的案例,但骨子里景况每每更糟。

三、本章涉及基本手艺点

图片 5

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test'); //连接到贰个test的数据库操作到此地大概是私家都会,可是接下去具体怎么开展数据库的操作,在未有实例的景况下仍有一点纠葛的。小编这里以一个记名注册为例来阐明什么行使。

错误 #4:期待回调函数以三只格局运营

异步程序的回调函数实际不是 JavaScript 和 Node.js 唯有的,但它们是产生回调函数流行的缘由。而对于别的编制程序语言,大家神不知鬼不觉地认为实施顺序是一步接一步的,如四个语句将会进行完第一句再实践第二句,除非那三个语句间有叁个明显的跳转语句。固然那样,它们常常局限于条件语句、循环语句和函数调用。

唯独,在 JavaScript 中,回调有些特定函数恐怕并不会及时运营,而是等到任务成功后才运营。上面例子即是直到未有其余职责,当前函数才运维:

JavaScript

function testTimeout() { console.log(“Begin”) setTimeout(function() { console.log(“Done!”) }, duration * 1000) console.log(“Waiting..”) }

1
2
3
4
5
6
7
function testTimeout() {
console.log(“Begin”)
setTimeout(function() {
console.log(“Done!”)
}, duration * 1000)
console.log(“Waiting..”)
}

您会静心到,调用 “test提姆eout” 函数会首先打字与印刷 “Begin”,然后打印“Waiting..”,紧接大概风姿罗曼蒂克秒后才打字与印刷 “Done!”。

其他一个内需在回调函数被触发后实行的东西,都要把它献身回调函数内。

四、内容

3、用webstorm创立五个新的Express App项目,那样就径直封装好了express(),省去了一心一德写的劳动。然后改良app.js如下:

错误 #5:用“exports”,而不是“module.exports”

Node.js 将每种文件视为三个孤立的小模块。要是您的包(package卡塔尔含有三个文件,恐怕是 “a.js” 和 “b.js”。因为 “b.js” 要博得 “a.js” 的作用,所以 “a.js” 必得透过为 exports 对象增加属性来导出它。

JavaScript

// a.js exports.verifyPassword = function(user, password, done) { ... }

1
2
// a.js
exports.verifyPassword = function(user, password, done) { ... }

当这样操作后,任何引进 “a.js” 模块的文件将会得到四个包涵属性方法 “verifyPassword” 的靶子:

JavaScript

// b.js require(‘a.js’) // { verifyPassword: function(user, password, done) { ... } }

1
2
// b.js
require(‘a.js’) // { verifyPassword: function(user, password, done) { ... } }

而是,如若大家想直接导出那一个函数,并不是用作有个别对象的属性呢?大家能经过覆盖 exports 对象来达到这一个指标,但大家不能够将它正是二个全局变量:

JavaScript

// a.js module.exports = function(user, password, done) { ... }

1
2
// a.js
module.exports = function(user, password, done) { ... }

注意,大家是如何将 “exports” 作为 module 对象的五个属性。在那间驾驭 “module.exports” 和 “exports” 之间不相同是足够重大的,並且那日常会产生 Node.js 开荒新手们发出挫败感。

4.1、新建users.js组件来封装【顾客】模块作用

废话十分的少说,先代码奉上:

书接上文,直接在models文件下新建意气风发users.js文本,代码如下:


var db = require('./mongodb');

function User(user) {

this.name = user.name;

this.password = user.password;

this.email = user.email;

};

module.exports = User;

//存款和储蓄顾客音讯

User.prototype.save = function(callback) {

//要存入数据库的客户文书档案

var user = {

name: this.name,

password: this.password,

email: this.email

};

//增添操作

var userModel = new db.Users(user);

userModel.save(function(err,user){

if(err){

console.err(err);

return callback(err);//错误,返回 err 信息

}

console.log("sucess:" user[0]);

callback(null, user[0]);//成功!err 为 null,并重回存款和储蓄后的客户文书档案

});

};

//读取顾客音信

User.get = function(name, callback) {

if (name){

db.Users.findOne({"name":name},

function(err,user){

if(err) {

console.err(err);

return callback(err);//失败!返回 err 信息

}

callback(null, user);//成功!重返查询的客商音讯

});

}else{

db.Users.find(null,

function(err,users){

if(err) {

console.err(err);

return callback(err);//失败!返回 err 信息

}

callback(null, users);//成功!再次来到查询的客户新闻

});

}

};


图片 6

  1. var db = require('./mongodb');

引入上节课创制的mongodb.js文件,今后会采取其导出的类实例。

  1. function User(user) {

this.name = user.name;

this.password = user.password;

this.email = user.email;

};

module.exports = User;

上述代码,利用函数的点子定义了意气风发User类,七个字段:name,password,email,并通module.exports的秘籍对外导出。

  1. User.prototype.save = function(callback) {

.....

}

上述代码,动态的为User类定义了生龙活虎静态属性,该属性实质是二个主意(function),该方法的意义是现在用来保存客户数量,注册客户时会用到,调用该方法成功后,会向Mongodb数据库的users文书档案中,插入一条记下,传入的参数:为一遍调函数,用于试行成功或战败后的操作。

  1. var userModel = new db.Users(user);

userModel.save(function(err,user){

......

})

上述代码,首先创立mongodb.js文件中程导弹出来Users模型实例,然后,主题的的确调用了mongodb数据库引擎向后台插入数据的代码是:userModel.save(function(err,user){......)
中间:save的几个参数,第叁个参数err为借使插入出错,选择服务器再次来到的荒谬对象,第4个参数user为假如插入成功,重回操作成功的user顾客实例集结。

5. 亟需小心的是:假诺插入成功,重回的user实际是二个聚众,这里由于是插入操作,这一个会集里将唯有一条记下,即大幅度增加的user实例,所以选择时,需求运用user[0]的方式,即:
callback(null, user[0]);//成功!err 为 null,并赶回存款和储蓄后的客商文书档案

6.对这几个User的save方法的调用代码,以往将肖似于以下那样:

var newUser = new User({

name: name,  //选取前台传递过来的顾客名

password: password, //选用前台传递过来的密码

email: req.body.email  //选拔前台传递过来的Email

});

......

newUser.save(function(err, user) {   //调用该User实例的save方法

if (err) {

res.send({ status: 'error', message: "出错了,原因如下:" err });

return;

}

res.send({ status: 'success', message: "注册成功!", user: user });

});

[javascript]
/**
 * Module dependencies.
 */ 
 
var express = require('express') 
  , routes = require('./routes') 
  , user = require('./routes/user') 
  , http = require('http') 
  , path = require('path') 
  , mongoose = require('mongoose');   //1  
 
 
var app = express(); 
 
 
// all environments  
app.set('port', process.env.PORT || 3000); 
app.set('views', __dirname '/views'); 
app.set('view engine', 'ejs'); 
app.use(express.favicon()); 
app.use(express.logger('dev')); 
app.use(express.bodyParser()); 
app.use(express.methodOverride()); 
app.use(app.router); 
app.use(express.static(path.join(__dirname, 'public'))); 
 
 
// development only  
if ('development' == app.get('env')) { 
  app.use(express.errorHandler()); 

 
 
app.get('/', routes.index); 
app.get('/log',routes.login); 
app.post('/log',routes.doLogin); 
app.get('/reg',routes.reg); 
app.post('/reg',routes.doReg); 
 
 
//mongoose  
mongoose.connect('mongodb://localhost/test_db');  //2 
 
 
http.createServer(app).listen(app.get('port'), function(){ 
  console.log('Express server listening on port ' app.get('port')); 
}); 

错误 #6:在回调函数内抛出荒诞

JavaScript 有个“十分”概念。万分管理与大好些个理念语言的语法相仿,比方 Java 和 C ,JavaScript 能在 try-catch 块内 “抛出(throw卡塔 尔(英语:State of Qatar)” 和 捕捉(catch卡塔 尔(英语:State of Qatar)格外:

JavaScript

function slugifyUsername(username) { if(typeof username === ‘string’) { throw new TypeError(‘expected a string username, got ' (typeof username)) } // ... } try { var usernameSlug = slugifyUsername(username) } catch(e) { console.log(‘Oh no!’) }

1
2
3
4
5
6
7
8
9
10
11
12
function slugifyUsername(username) {
if(typeof username === ‘string’) {
throw new TypeError(‘expected a string username, got ' (typeof username))
}
// ...
}
 
try {
var usernameSlug = slugifyUsername(username)
} catch(e) {
console.log(‘Oh no!’)
}

可是,固然您把 try-catch 放在异步函数内,它会胜出你意料,它并不会实行。举例,就算您想维护后生可畏段含有超级多异步活动的代码,并且这段代码满含在三个 try-catch 块内,而结果是:它不肯定会运转。

JavaScript

try { db.User.get(userId, function(err, user) { if(err) { throw err } // ... usernameSlug = slugifyUsername(user.username) // ... }) } catch(e) { console.log(‘Oh no!’) }

1
2
3
4
5
6
7
8
9
10
11
12
try {
db.User.get(userId, function(err, user) {
if(err) {
throw err
}
// ...
usernameSlug = slugifyUsername(user.username)
// ...
})
} catch(e) {
console.log(‘Oh no!’)
}

假定回调函数 “db.User.get” 异步触发了,即使功能域里带有的 try-catch 块离开了上下文,如故能捕捉那多少个在回调函数的抛出的荒诞。

那就是 Node.js 中什么管理错误的别的生机勃勃种方法。其它,有无法缺乏据守全体回调函数的参数(err, …卡塔 尔(阿拉伯语:قطر‎情势,全体回调函数的首先个参数期望是八个不当对象。

  1. User.get = function(name, callback) {......})

上述代码,动态的为User类定义了风度翩翩静态属性get,该属性实质是二个办法(function),该办法的法力是用以通过顾客名拿到顾客新闻.四个参数,第二个参数name:客户名,第2个参数callback:查询成功或战败后的回调函数。

  1. 客商查找的着力数据库操作代码是:

db.Users.findOne({"name":name},function(err,user){......})
db.Users.find(null,function(err,users){......})
只顾findOne与find的区分,三个是寻找一个单纯顾客(不管查到有个别许条记下,均只回去第一条记下卡塔 尔(阿拉伯语:قطر‎,所以回调里再次来到值是user,而 find查找找重返全体适合条件的,所以是个会集users

  1. 后天对User.get方法的调用的客商端代码,将相仿于:

//检查顾客名是不是业已存在

User.get(newUser.name, function(err, user) {

if (err) {

res.send({ status: 'error', message: "出错了,原因如下:" err });

return;

}

if (user) {

res.send({ status: 'failed', message: "客商已存在!" });

return;

})

/**
 * Module dependencies.
 */

错误 #7:认为数字是整型

数字在 JavaScript 中都是浮点型,JS 没有整型。你或然无法预料到那将是二个主题素材,因为数大到过量浮点型范围的景况并不平淡无奇。

JavaScript

Math.pow(2, 53) 1 === Math.pow(2, 53)

1
Math.pow(2, 53) 1 === Math.pow(2, 53)

噩运的是,在 JavaScript 中,这种关于数字的光怪陆离意况远不止于此。即使数字都是浮点型,对于上面的表明式,操作符对于整型也能健康运作:

JavaScript

5 >> 1 === 2 // true

1
5 >> 1 === 2 // true

不过,不像算术运算符那样,位操作符和活动操作符只可以操作后 34人,有如 “整型” 数。举例,尝试位移 “Math.pow(2,53)” 1 位,会收获结果 0。尝试与 1 举办按位或运算,得到结果 1。

JavaScript

Math.pow(2, 53) / 2 === Math.pow(2, 52) // true Math.pow(2, 53) >> 1 === 0 // true Math.pow(2, 53) | 1 === 1 // true

1
2
3
Math.pow(2, 53) / 2 === Math.pow(2, 52) // true
Math.pow(2, 53) >> 1 === 0 // true
Math.pow(2, 53) | 1 === 1 // true

你只怕相当少要求管理一点都不小的数,但万风姿潇洒你真正要拍卖的话,有好些个大整型库能对大型精度数完结着重的数学生运动算,如  node-bigint。

4.2、新建post.js组件来封装【博客小说】模块功能

三回九转!在models文件下新建大器晚成posts.js文书,代码如下:


var db = require('./mongodb');

function Post(name, title, post) {

this.name = name;

this.title = title;

this.post = post;

}

module.exports = Post;

//存款和储蓄生机勃勃篇小说及其有关音信

Post.prototype.save = function(callback) {

var date = new Date();

//存储各样时间格式,方便以往增添

var time = {

date: date,

year : date.getFullYear(),

month : date.getFullYear() "-" (date.getMonth() 1),

day : date.getFullYear() "-" (date.getMonth() 1) "-" date.getDate(),

minute : date.getFullYear() "-" (date.getMonth() 1) "-" date.getDate() " "

date.getHours() ":" (date.getMinutes() < 10 ? '0' date.getMinutes() : date.getMinutes())

}

//要存入数据库的文档

var post = {

name: this.name,

time: time,

title: this.title,

post: this.post  //文章

};

var postModel = new db.Posts(post);

postModel.save(function(err){

if(err){

return callback(err);//错误,返回 err 信息

}

callback(null);//成功!

});

};

//读取文章及其有关新闻

Post.get = function(name, callback) {

var query = {};

if (name) {

query.name = name;

}

db.Posts.find(query).sort({time:-1}).find(null,function (err, docs) {

if (err) {

return callback(err);//失败!返回 err

}

callback(null, docs);//成功!以数组方式重临查询的结果

});

}


图片 7

  1. var db = require('./mongodb');

引进上节课创制的mongodb.js文件,现在会动用其导出的类实例。

  1. function Post(name, title, post) {

this.name = name;

this.title = title;

this.post = post;

}

module.exports = Post;

上述代码,利用函数的秘籍定义了大器晚成Post类,四个字段:name,title,post,含义与上节课定义的数据模型字段生机勃勃致,并通module.exports的不二秘技对外导出。

  1. Post.prototype.save = function(callback) {

.....

}

上述代码,动态的为Post类定义了生机勃勃静态属性,该属性实质是多少个方法(function),该方式的效应是他日用于保存顾客宣布的博文内容,顾客宣布随笔时会用到,调用该措施成功后,会向Mongodb数据库的posts文书档案中,插入一条记下,传入的参数callback:为叁次调函数,用于实践成功或破产后的操作。

  1.  var postModel = new db.Posts(post);

postModel.save(function(err){

......

})

上述代码,首先创立mongodb.js文件中程导弹出来Posts模型实例,然后,宗旨的的确调用了mongodb数据库引擎向后台插入数据的代码是:postModel.save(function(err){......)

个中:参数err为尽管插入出错,选取服务器重回的失实对象,第壹个参数省去,因为无需。

  1. 对这些Post的save方法的调用代码,现在将形似于以下这样:

.....

post = new Post(currentUser.name, req.body.title, req.body.post);

//console.log(post);

post.save(function(err) {

if (err) {

res.send({ status: 'failed', message: "出错了,原因如下:" err });

} else {

res.send({ status: 'successed', message: "保存成功!" });

}

});

  1. Post.get = function(name, callback) {......})

上述代码,动态的为Post类定义了后生可畏静态属性get,该属性实质是三个艺术(function),该情势的效应是用于通过客商名获得该客商发布的博文音信.多个参数,第二个参数name:客商名,第贰个参数callback:查询成功或退步后的回调函数。

  1. var query = {};

if (name) {

query.name = name;

}

这段代码的情趣是,假若从询问参数中获得到name值,则表明要收获某客商的博客列表,若无的话,表达要找出全部客商的博客新闻

  1. db.Posts.find(query).sort({time:-1}).find(null,function (err, docs) {......})

这段代码是中央的操作数据库查询的代码,依照query传递的值来对posts集合(表卡塔尔举办查询,假使query为空({}),则表达无条件查询(即查询全体卡塔 尔(英语:State of Qatar)。sort({time:-1})的野趣是对查询的结果定期间倒序排列。find(null,function(err,docs){....})  ,在那之中的回调函数的第二参数,即用来收取从数据库中查询到相符条件的“博客小说内容”,注意:它是叁个集结。

  1. 对Post.get方法调用的客户端示例代码:

Post.get(username, function(err, posts) {

if (err) {

posts = [];

}

res.send(posts);

});

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path')
  , mongoose = require('mongoose');   //1

错误 #8:忽略了 Streaming(流) API 的优势

世家都在说想创设一个Mini代理服务器,它能响应从别的服务器获取内容的央浼。作为二个案例,大家将创设三个供应 Gravatar 图像的微型 Web 服务器:

JavaScript

var http = require('http') var crypto = require('crypto') http.createServer() .on('request', function(req, res) { var email = req.url.substr(req.url.lastIndexOf('/') 1) if(!email) { res.writeHead(404) return res.end() } var buf = new Buffer(1024*1024) http.get(''), function(resp) { var size = 0 resp.on('data', function(chunk) { chunk.copy(buf, size) size = chunk.length }) .on('end', function() { res.write(buf.slice(0, size)) res.end() }) }) }) .listen(8080)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var http = require('http')
var crypto = require('crypto')
 
http.createServer()
.on('request', function(req, res) {
var email = req.url.substr(req.url.lastIndexOf('/') 1)
if(!email) {
res.writeHead(404)
return res.end()
}
 
var buf = new Buffer(1024*1024)
http.get('http://www.gravatar.com/avatar/' crypto.createHash('md5').update(email).digest('hex'), function(resp) {
var size = 0
resp.on('data', function(chunk) {
chunk.copy(buf, size)
size = chunk.length
})
.on('end', function() {
res.write(buf.slice(0, size))
res.end()
})
})
})
.listen(8080)

在这里个非常例子中有一个 Node.js 难点,我们从 Gravatar 获取图像,将它读进缓存区,然后响应诉求。那不是二个多么不佳的难点,因为 Gravatar 再次来到的图像实际不是相当大。不过,想象一下,如若大家代理的原委大小有不胜枚举兆。那就有叁个更加好的艺术了:

JavaScript

http.createServer() .on('request', function(req, res) { var email = req.url.substr(req.url.lastIndexOf('/') 1) if(!email) { res.writeHead(404) return res.end() } http.get(''), function(resp) { resp.pipe(res) }) }) .listen(8080)

1
2
3
4
5
6
7
8
9
10
11
12
13
http.createServer()
.on('request', function(req, res) {
var email = req.url.substr(req.url.lastIndexOf('/') 1)
if(!email) {
res.writeHead(404)
return res.end()
}
 
http.get('http://www.gravatar.com/avatar/' crypto.createHash('md5').update(email).digest('hex'), function(resp) {
resp.pipe(res)
})
})
.listen(8080)

此地,大家获取图像,并简要地因此管道响应给顾客端。绝没有供给我们在响应以前,将全体内容读取到缓冲区。

五、后述

本章代码下载:

下章剧透:

《项目实战:基于Angular2 Mongodb Node手艺实现的多顾客博客系统教程(9卡塔 尔(阿拉伯语:قطر‎》

                                                      --  达成Node后台的客商登入模块&参预Session辅助

图片 8

var app = express();

错误 #9:把 Console.log 用于调节和测验目标

在 Node.js 中,“console.log” 允许你向调整台打字与印刷差不离全体东西。传递二个对象给它,它会以 JavaScript 对象字面量的方式打字与印刷出来。它承担放肆五个参数,并以空格作为分隔符打字与印刷它们。有众多少个理由让开荒者很想用那些来调度(debug卡塔 尔(英语:State of Qatar)本身的代码;不过,作者猛烈提出你防止在真的程序里使用 “console.log” 。你应该防止在任何代码里使用 “console.log” 实行调节和测量试验(debug卡塔 尔(英语:State of Qatar),当没有必要它们的时候,应注释掉它们。相反,使用特地为调节和测量检验创立的库,如:debug。

当你从头编写制定应用程序时,这个库能方便地开行和剥夺某行调节和测量检验(debug卡塔尔成效。比方,通过不安装 DEBUG 遭受变量,能够免止全部调节和测施行被打字与印刷到终端。使用它不会细小略:

JavaScript

// app.js var debug = require(‘debug’)(‘app’) debug(’Hello, %s!’, ‘world’)

1
2
3
// app.js
var debug = require(‘debug’)(‘app’)
debug(’Hello, %s!’, ‘world’)

为了运维调节和测施行,将情形变量 DEBUG 设置为 “app” 或 “*”,就能够大致地运营这几个代码了:

JavaScript

DEBUG=app node app.js

1
DEBUG=app node app.js

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

错误 #10:不行使管理程序

无论你的 Node.js 代码运维在坐褥条件依然地方开辟情状,三个监理处理程序能很好地保管你的主次,所以它是一个卓越管用并值得全部的东西。开辟者设计和完毕今世利用时平常推荐的五个超级级施行是:火速退步,神速迭代。

设若产生二个预料之外的荒唐,不要试图去管理它,而是让您的次第崩溃,并有个监察和控制者在几秒后重启它。管理程序的裨益不独有是重启崩溃的主次。那么些工具允许你重启崩溃的次第的还要,也同意文件发出变动时重启程序。那让开辟Node.js 程序成为大器晚成段更欢悦的体会。

有超级多 Node.js 可用的管住程序。比如:

  • pm2
  • forever
  • nodemon
  • supervisor

具有那个工具齐镳并驱。一些惠及在同一个机械里管理多少个应用程序,而别的擅专长日志管理。然则,倘诺您想开首使用这几个程序,它们都是很好的精选。

// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}

总结

正如你所精晓的那么,一些 Node.js 难点能对你的主次变成消亡性打击。而有的则会在你品味成功最轻易易行的事物时,让你生出挫败感。固然Node.js 的开荒门槛比较低,但它依然有相当轻易搞混的地点。从其余编制程序语言转过来学习 Node.js 开采者或然会遇见那些主题材料,但那几个不当在 Node.js 生手中也是拾分周围的。幸运的是,它们超轻便幸免。笔者盼望以此大致带领能协理Node.js 新手写出更杰出的代码,并为我们付出出牢固神速的软件。

打赏援救作者翻译更加多好文章,感激!

打赏译者

app.get('/', routes.index);
app.get('/log',routes.login);
app.post('/log',routes.doLogin);
app.get('/reg',routes.reg);
app.post('/reg',routes.doReg);

打赏扶植自身翻译更加多好小说,多谢!

任选生机勃勃种支付格局

图片 9 图片 10

1 赞 7 收藏 1 评论

//mongoose
mongoose.connect('mongodb://localhost/test_db');  //2

有关作者:刘健超-J.c

图片 11

前端,在路上... 个人主页 · 作者的篇章 · 19 ·     

图片 12

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' app.get('port'));
});

4、接下去定义一下Schema和Model,这几个正是数量库表的布局。在档案的次序根路线下创办多少个models的文件夹,里面加多四个user.js用来定义客户表。models/user.js代码如下。

[javascript]
var mongoose = require('mongoose') 
    , Schema = mongoose.Schema 
    , ObjectId = Schema.ObjectId; 
 
var UserSchema = new Schema({ 
      name: String 
    , password: String 
}); 
 
module.exports = mongoose.model('User', UserSchema); 

var mongoose = require('mongoose')
    , Schema = mongoose.Schema
    , ObjectId = Schema.ObjectId;

var UserSchema = new Schema({
      name: String
    , password: String
});

module.exports = mongoose.model('User', UserSchema);注意最毕生龙活虎行,这里是一向把UserSchema的Model给导出去了,也能够直接导出UserSchema,module.exports = UserSchema,也才这样做的话,再用那一个表新闻的时候就得单独Model一下。

 

5、引进mongoose后,自个儿加上相应的文件,在view里新建登入注册页,尾部尾巴部分这几个含有文件也都要好建。先说注册页,表单管理路线为/reg。注意客商名密码的输入框作者是一贯用name="user[]"这种样式,那样前边能够一向通过这几个user来获取相关音信,其实不这么也足以。
[javascript]
<% include header.ejs %> 
<form action="/reg" method="post"> 
<input type="text" name="user[name]" /> 
<input type="password" name="user[password]" /> 
<input type="submit" value="Register" /> 
</form> 
<% include footer.ejs %> 

<% include header.ejs %>
<form action="/reg" method="post">
<input type="text" name="user[name]" />
<input type="password" name="user[password]" />
<input type="submit" value="Register" />
</form>
<% include footer.ejs %>接下去改过doReg方法,那是拍卖登记事件的函数。
6、校正index.js,因为想在那处登记时候把数据存入到数据库中,所以那边须求援引上边第四步成立的model。具体代码如下所示。

[javascript]
var User = require('../models/user'); 
/*
 * GET home page.
 */ 
 
 
exports.index = function(req, res){ 
  User.find({}, function (err,users) { 
      res.render('index', { title: 'Express',users:users }); 
  }); 
}; 
 
exports.reg=function(req,res){ 
    res.render('reg',{title:'Register Page'}); 
}; 
exports.doReg=function(req,res){ 
    var user = new User(req.body.user); 
    user.save(function (err, user) { 
        if(!err) { 
            console.log(user); 
            res.redirect('/') 
        } 
    }); 
    console.log(req.body.user); 
}; 

var User = require('../models/user');
/*
 * GET home page.
 */

exports.index = function(req, res){
  User.find({}, function (err,users) {
      res.render('index', { title: 'Express',users:users });
  });
};

exports.reg=function(req,res){
    res.render('reg',{title:'Register Page'});
};
exports.doReg=function(req,res){
    var user = new User(req.body.user);
    user.save(function (err, user) {
        if(!err) {
            console.log(user);
            res.redirect('/')
        }
    });
    console.log(req.body.user);
};这一步要注意为什么是req.body.user,这里正是前方写页面一直用user[]这种方式带给的功利,借使单独写name="username",那么这里就应该是上面这种格局。
[javascript]
var user = new User({ 
    name:req.body['username'], 
    password:req.body['password'] 
}); 

var user = new User({
 name:req.body['username'],
 password:req.body['password']
});user.save正是把刚刚多少提交到数据库,具体行使办法参看官方文书档案。save成功之后施行什么样操作就和好发挥吗。保存在此以前也足以拓宽部分简便的表单验证等等。

7、通过登入来说怎样从数据库抽取数据,继续修正index.js,如下所示。

[javascript]
var User = require('../models/user'); 
/*
 * GET home page.
 */ 
 
exports.index = function(req, res){ 
  User.find({}, function (err,users) { 
      res.render('index', { title: 'Express',users:users }); 
  }); 
}; 
exports.login=function(req,res){ 
    res.render('log',{title:'Login Page'}); 
} ; 
exports.doLogin=function(req,res){ 
    var user = req.body.user; 
    User.find(user,function(err,docs){ 
        if(!err){ 
            if(docs!=''){ 
                console.log(docs);                 
                return res.redirect('/'); 
            } else{ 
                console.log('客户名或密码不许确'); 
                return res.redirect('/log'); 
            } 
 
        }else{ 
            console.log("Something happend."); 
        } 
    }) 
}; 
exports.reg=function(req,res){ 
    res.render('reg',{title:'Register Page'}); 
}; 
exports.doReg=function(req,res){ 
    var user = new User(req.body.user); 
    user.save(function (err, user) { 
        if(!err) { 
            console.log(user); 
            res.redirect('/') 
        } 
    }); 
    console.log(req.body.user); 
}; 

var User = require('../models/user');
/*
 * GET home page.
 */

exports.index = function(req, res){
  User.find({}, function (err,users) {
      res.render('index', { title: 'Express',users:users });
  });
};
exports.login=function(req,res){
    res.render('log',{title:'Login Page'});
} ;
exports.doLogin=function(req,res){
    var user = req.body.user;
    User.find(user,function(err,docs){
        if(!err){
            if(docs!=''){
                console.log(docs);               
                return res.redirect('/');
            } else{
                console.log('客户名或密码不许确');
                return res.redirect('/log');
            }

        }else{
            console.log("Something happend.");
        }
    })
};
exports.reg=function(req,res){
    res.render('reg',{title:'Register Page'});
};
exports.doReg=function(req,res){
    var user = new User(req.body.user);
    user.save(function (err, user) {
        if(!err) {
            console.log(user);
            res.redirect('/')
        }
    });
    console.log(req.body.user);
};
那边通过find()方法来查询数据库,使用办法不表明了。第多少个参数user便是要查询的数额,从输入框获取过来的,假设不是用user[]这种方式定义的name属性,那么这里相通的用{naem:req.body['username'],password:req.body['password']}那样的写法。回调函数docs正是从数据库查询再次回到的结果。

 

事例到此结束。

 

npm install mongoose 2、连接mongodb数据库,在app.js里面增加如下两行代码。 [javascript] var...

本文由星彩网app下载发布于前端技术,转载请注明出处:个多如牛毛错误,项目实战

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。