个人总结,仅供参考,详细内容请 参考官方教程:
github项目源代码:代码链接
终端下载git clone https://github.com/RobinsonKO/node-blog.git
推荐文章:git详细入门攻略
1、环境搭配与项目创建
node.js
1、模块机制
- CommonJS规范出发点:
-JavaScript没有模块系统
- 标准库少。ECMAScript仅定义了部分核心库,对于文件系统,I/O流等常见需求没有标准API
- 没有标准接口。没用定义Web服务器或者数据库的标准统一接口
- 缺乏包管理系统。没有自动加载和安装依赖的能力 - 模块规范
2、异步I/O
3、事件与回调函数
Express
1、创建项目
参考:创建一个项目,项目整体框架介绍
npm istall express-generator -g
express -h
express -e blog
2、使用中间件
一个express项目中包含以下几类中间件,熟悉这几类中间件之后,在去分析app.js中的内容就清晰多了。
- 应用层中间件
- 路由层中间件
- 错误处理层中间件
- 内建中间件
- 第三方中间件
应用层中间件是通过app实例对象使用app.use()、app.METHOD()使用的,例如:
var app = express();
app.use(function (req, res, next) {
console.log('Time: ',Date.now();
next();
};
app.get('/user, function(req, res ,next) {
res.send('USER');
};
路由层中间件和应用层中间件类似,只是通过Router实例对象使用use()、METHOD()方法,例如:
var express = require('express');
var Router = express.Router();
router.use(function (req, res, next) {
console.log('Time: ',Date.now();
next();
};
router.get('/user, function(req, res ,next) {
res.send('USER');
};
- router和app的区别:
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
错误处理中间件必须包含4个参数,即使不使用next对象,例如:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
- 传递给next()的任何参数(除了 route),Express都会把它当做当前请求出错,之后会跳过后续的非错误处理路由和中间件,如果没有自定义的错误处理,就会调用Express默认的错误处理函数
- next(route):跳过同一个路由当中后续回调函数,例如:
router.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next router
if (req.params.id == 0) next('route');
// otherwise pass control to the next middleware function in this stack
else next(); //
}, function (req, res, next) {
// render a regular page
res.render('regular');
});
// handler for the /user/:id path, which renders a special page
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id);
res.render('special');
});
从4.x版本之后,Express就不在依赖Connect,除了express.static之外,其他的中间件都作为独立的第三方中间件使用,第三方中间件的使用方法为,例如使用cookie-parser
npm install cookie-parser --save
var CookiePaser = require('cookie-parser);
var app = express();
app.use(CookieParser());
建议独自查看:官方教程
2、连接数据库与基本操作
mongodb数据库(作为本地服务?)
- MongoDB基本管理命令
- Mongoose学习参考文档——基础篇
关于Schema、Model、Entity的说明非常精辟 - MVC中的M
3、配置会话
什么是Cookie、Session
- Cookie:HTTP是无状态的协议,但现实中的业务处理需要一定的状态,否者就无法区分不同的用户。比如说无需登录京东就可以添加购物车,你每一次添加的物品(多次请求)都到了同一个购物车。这就需要使用Cookie(存在于报文中)来标识和认证同一个账户。(前后端都可以操作Cookie)
- Cookie在浏览器和服务器的协作处理分下面几步
-服务器向浏览器发送Cookie
-浏览器将Cookie保存
-之后每次浏览器都会想服务器发送Cookie - Session:由于在前后端都可以操作Cookie,所以有时使用Cookie是不安全的。比如需要更具Cookie中的isVIP字段来判断业务逻辑,但是前端可以篡改它来达到伪造的目的。而Session只保存在后端,对前端不可见,因此对于数据敏感的操作,就需要用到Session。(Session有效期限短)
- 基于Cookie来实现用户与数据的映射:服务器生成Session口令,传递Cookie,通过Cookie口令与Session口令来实现用户与数据的映射。一旦篡改了Cookie口令,就无法完成映射。并且Session口令过期时间短,之后再生成新的口令,这也是为什么登陆京东一段时间不操作就需要重新登陆。
配置本地session
//app.js
var express = require('express')
, cookieParser = require('cookie-parser')
, session = require('express-session')
, app = express()
app.use(cookieParser()) // required before session.
app.use(session({
secret: 'keyboard cat',
key: 'sid',
cookie: { secure: true, maxAge: 60000 }
})
)
Session数据并不是保存在Cookie中,反而用到了Cookie,所以必须提前使用[cookie-parser]
Options
key
- cookie name defaulting toconnect.sid
.store
- session store instance.secret
- session cookie is signed with this secret to prevent tampering.proxy
- trust the reverse proxy when setting secure cookies (via “x-forwarded-proto”).cookie
- session cookie settings, defaulting to{ path: '/', httpOnly: true, secure: false, maxAge: null }
// routes/index.js 打印出Cookie、Session
app.get('/', function(req, res) {
console.log("Cookies: ", req.cookies);
console.log("Session: ", req.session);
})
通过req.cookies 、 req.session 获取相应cookie,session信息
配置session到mongodb
//app.js
var mongoose = require('mongoose');
, MongoStore = require('connect-mongo')(express);
// Basic usage
mongoose.connect('mongodb://localhost/blog');
app.use(session({
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
使用req.flash()
//app.js
var flash = require('connect-flash');
app.use(express.cookieParser('keyboard cat'));
app.use(session({
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(flash());
// routes/index.js 测试
router.post('/reg', function(req, res) {
//检查用户两次输入的口令是否一致
if (req.body['password-repeat'] != req.body['password']) {
req.flash('error','两次输入密码口令不一致');
console.log("Session: ", req.session);//错误时,显示flash信息
return res.redirect('/reg');
}
...
}
/* 后台打印出的Session信息
Session: Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
flash: { error: [ '两次输入的口令不一致' ] },
user: null }
*/
flash保存住Session中,通过flash中的变量自会在用户当前和下一次请求中被访问,之后就会被删除,通常与重定位redirect一起使用,可以方便的实现页面的通知和错误信息显示
在项目中的使用
// routes/index.js
router.post('/reg', function(req, res) {
...
req.session.user = UserEntity;
...
}
function checkLogin(req,res,next) {
if (!req.session.user) {
req.flash('error','未登录');
return res.redirect('/login');
}
next();
}
通过把用户保存到Session中,来区分用户是否登录和区分不同用户
// res.local 属性 把error等属性注册views层全局变量,生命周期为一次request请求,从而实现动态视图
app.use(function(req, res, next){
console.log("Comes to DynamicHelper");
res.locals.user = req.session.user;
res.locals.post = req.session.post;
var error = req.flash('error');
res.locals.error = error.length ? error : null;
var success = req.flash('success');
res.locals.success = success.length ? success : null;
next();
});
- res.locals:
An object that contains response local variables scoped to the request, and therefore available only to the view(s) rendered during that request / response cycle (if any). Otherwise, this property is identical to app.locals.
This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on.