个常见错误,Node技术落成的多用户博客系统教程

NodeJS 开发者的 10 个常见错误

2015/06/16 · CSS · 1
评论

本文由 伯乐在线 –
刘健超-J.c
翻译,黄利民
校稿。未经许可,禁止转发!
英文出处:www.toptal.com。欢迎到场翻译组。

自 Node.js
公诸于世的那一刻,就伴随着表扬和批评的鸣响。那几个争辩仍在不断,而且并不会很快破灭。而我辈平常忽视掉这几个争议暴发的案由,每种编程语言和平台都是因某些难点而备受批评,而那些标题标发生,是取决于大家什么样行使这几个平台。不管有多难才能写出安全的
Node.js
代码,或有多简单写出高并发的代码,该平台已经有极度长一段时间,并已被用来建立一个数额庞大、稳健和老成的
web 服务器。那个 web 服务器伸缩性强,并且它们经过在 Internet
上安居的周转时刻,注明自己的平稳。

唯独,像其余平台一样,Node.js
不难因开发者难点而饱受批评。一些荒唐会下跌品质,而其他一些题材会让
Node.js 直接崩溃。在那篇文章里,大家将会聊一聊关于 Node.js 新手的 10
个常犯错误,并让他俩知晓什么幸免这几个错误,从而成为一名 Node.js 高手。

亚洲必赢官网 1

本章主要讲哪些(一句话)?

本章主要讲解:利用mongoose第三方库开展作业数据操作

亚洲必赢官网 2

                                                  —  

 1、起头采纳mongoose时,得先安装,打开命令行,执行$ npm install mongoose

#  Node.js学习笔记

错误 #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
建立命令行工具的一局地,整个东西一块运行是没难题的),然后那或许没难题。不过,在
Node.js
服务器实例尝试同时服务广大个用户的情景下,那将是一个毁灭性的题材。

一经用户数组是从数据库检索出来的,有个解决办法是,先在数据库中排序,然后再一直搜索。如果因急需总结庞大的金融交易历史数据总和,而导致堵塞事件循环,那足以创设额外的worker
/ queue 来幸免阻塞事件循环。

正如您所见到的,那从没新技巧来缓解这类 Node.js
难题,而每种情景都亟需单独处理。而基本解决思路是:不要让 Node.js 实例的主线程执行 CPU 密集型工作 –
客户端同时链接时。

一、前言

上一章重点对项目引入MongoDB举行多少存储,并导入mongoose第三方组件,完结mongodb数据库配置及连接代码,本节继续。

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

## 简介

– 编写高性能互联网服务器的JavaScript工具包

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

– 特点:快,耗内存多

– PHP是单线程,耗内存少速度相对慢些

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

JavaScript
一向都是依靠于回调函数。在浏览器中,处负责人件是通过调用函数(寻常是匿名的),那些动作就像回调函数。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

[javascript]
var mongoose = require(‘mongoose’); 
mongoose.connect(‘mongodb://localhost/test’); //连接到一个test的数量库 

## 在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”);

个常见错误,Node技术落成的多用户博客系统教程。};

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”)

“`


而正是由于那种异步操作,即使想要将读取的文本内容再次来到给客户端,就要接纳“闭包”的措施

“`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数据库

### 直接连接(不常用,需通晓)

– 安装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语句,第四个是插入的数额,第七个是匿名回调函数处理报错;传的值一定要和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(fields);       
//fields为查询暴发的新闻,不是查询结果,一般没什么用

})

//单独查询

connection.query(‘SELECT * from user where
uid=?’,[2],function(err,rs,fields){  //查询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-20个三番五次放在连接池中,当有访问需一而再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()  //将连接放回连接池

    });

})

“`

错误 #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为假设插入出错,接收服务器再次回到的一无可取对象,第四个参数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)” 和
捕捉(catch)至极:

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:用户名,第四个参数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

然则,不像算术运算符那样,位操作符和运动操作符只好操作后 32
位,就像 “整型” 数。例如,尝试位移 “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为空({}),则申明无条件查询(即查询所有)。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 的优势

我们都说想建立一个微型代理服务器,它能响应从其他服务器获取内容的请求。作为一个案例,大家将创设一个供应
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)自己的代码;但是,我强烈提出你制止在真的程序里使用
“console.log” 。你应当避免在方方面面代码里使用 “console.log”
举行调试(debug),当不要求它们的时候,应注释掉它们。相反,使用专门为调试建立的库,如: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…

网站地图xml地图