Node.js借助事件驱动,非阻塞I/O模型变得轻量和高效,非常适合运行在分布式设备的数据密集型的实时应用。

1、我们只需知道三点就知道exports和module.exports的区别了:
a、module.exports 初始值为一个空对象 {}
b、exports 是指向的 module.exports 的引用
c、require() 返回的是 module.exports 而不是 exports
1、a、require可加载.js、.json和.node后缀的文件;b、require的过程是同步的;c、require目录的机制是:如果目录下有package.json并指定了main字段,则用之;如果不存在package.json,则依次尝试加载目录下的index.js和index.node。d、require过的文件会加载到缓存,所以多次require同一个文件(模块)不会重复加载。e、判断是否是程序的入口文件有两种方式:require.main === module(推荐)、module.parent === null。
2、环境变量不属于Node.js的知识范畴,只不过我们在开发Node.js应用时经常与环境变量打交道,简单来讲,环境变量就是传递参数给运行程序的。
3、package.json对于Node.js应用来说是一个不可或缺的文件,它存储了该Node.js应用的名字、版本、描述、作者、入口文件、脚本、版权等等信息。语义化版本(semver)即dependencies、devDependencies和peerDependencies里的如:”co”: “^4.6.0”。
semver 格式:主版本号.次版本号.修订号。版本号递增规则如下:
主版本号:做了不兼容的API修改
次版本号:做了向下兼容的功能性新增
修订号:做了向下兼容的bug修正
4、直接使用npm i安装的模块是不会写入package.json的dependencies(或devDependencies),npm i express –save –save-exact (安装express,同时将”express”: “4.14.0”写入dependencies),将固定版本号写入dependencies,建议线上的Node.js应用都采取这种锁定版本号的方式,因为你不可能保证第三方模块下个小版本是没有验证bug的,即使是很流行的模块。运行以下命令:npm config set save-exact true。这样每次npm i xxx –save的时候会锁定依赖的版本号,相当于加了–save-exact参数。
为了彻底锁定依赖的版本,让你的应用在任何机器上安装的都是同样版本的模块(不管嵌套多少层),通过运行npm shrinkwrap,会在当前目录下产生一个npm-shrinkwrap.json,里面包含了通过node_modules计算出的模块的依赖树及版本。npm shrinkwrap只会生成dependencies的依赖,不会生成devDependencies的。只要目录下有npm-shrinkwrap.json则运行npm install的时候会优先使用npm-shrinkwrap.json进行安装,没有则使用package.json进行安装。
5、npm config set命令将配置写到了~/.npmrc文件,运行npm config list查看。
6、npm的scripts有一些内置的缩写命令,如常用的:npm start等价于npm run start、npm test等价于npm run test。
7、node –v8-options 查看harmony细节。express使用了path-to-regexp模块实现的路由匹配。从http://node.green上可以看到Node.js各个版本对ES6的支持情况。
8、在开发过程中,每次修改代码保存后,我们都需要手动重启程序,才能查看改动的效果。使用supervisor可以解决这个繁琐的问题,supervisor会监听当前目录下node和js后缀的文件,当这些文件发生改动时,supervisor会自动重启程序。

8、Promise用于异步流程控制,生成器与yield也能实现流程控制(基于co),async/await结合Promise也可以实现流程控制。
9、下面介绍几个常用的req的属性:
a、req.query:解析后的url中的querystring,如?name=haha,req.query的值为{name: ‘haha’}
b、req.params:解析url中的占位符,如/:name,访问/haha,req.params的值为{name: ‘haha’}
c、req.body:解析后的请求体,需使用相关的模块,如body-parser,请求体为{“name”: “haha”},则req.body为{name: ‘haha’}
10、在实际开发中通常有几十甚至上百的路由,都写在index.js既臃肿又不好维护,这时可以使用express.Router实现更优雅的路由解决方案。我们将/和/users/:name的路由分别放到了routes/index.js和routes/users.js中,每个路由文件通过生成一个express.Router实例router并导出,通过app.use挂载到不同的路径。
10、模板引擎(Template Engine)是一个将页面模板和数据结合起来生成html的工具。模板引擎有很多,ejs是其中一种,因为它使用起来十分简单,而且与express集成良好。通过app.set设置模板引擎为ejs和存放模板的目录。ejs有3种常用标签:<% code %>—运行JavaScript代码,不输出;<%= code %>—显示转义后的HTML内容;<%- code %>—显示原始HTML内容。

1
2
3
4
5
<ul>
<% for(var i=0; i<supplies.length; i++) {%>
<li><%= supplies[i] %></li>
<% } %>
</ul>

11、res.render函数渲染ejs模板,res.render第一个参数是模板的名字,第二个参数是传给模板的数据。res.render的作用就是将模板和数据结合生成html,同时设置响应头中的Content-Type: text/html,告诉浏览器我返回的是html,不是纯文本,要按html展示。
12、我们讲解了express中路由和模板引擎ejs的用法,但express的精髓并不在此,在于中间件的设计理念。中间件返回的响应是随意的,可以响应一个HTML错误页面、一句简单的话、一个JSON字符串,或者其他任何您想要的东西。
13、中间件与next:express中的中间件(middleware)就是用来处理请求的,当一个中间件处理完,可以通过调用next()传递给下一个中间件,如果没有调用next(),则请求不会往下传递,如内置的res.render其实就是渲染完html直接返回给客户端,没有调用next(),从而没有传递给下一个中间件。
14、通过app.use加载中间件,在中间件中通过next将请求传递到下一个中间件,next可接受一个参数接收错误信息,如果使用了next(error),则会返回错误而不会传递到下一个中间件。app.use有非常灵活的使用方式。
15、express有成百上千的第三方中间件,在开发过程中我们首先应该去npm上寻找是否有类似实现的中间件,尽量避免造轮子,节省开发时间。express@4之前的版本基于connect这个模块实现的中间件的架构,express@4及以上的版本则移除了对connect的依赖自己实现了,理论上基于connect的中间件(通常以connect-开头,如connect-mongo)仍可结合express使用。
15、next(new Error(‘haha’)),express内置了一个默认的错误处理器,为我们自动返回了错误栈信息(Express内置了一个错误处理句柄,它可以捕获应用中可能出现的任意错误。这个缺省的错误处理中间件将被添加到中间件堆栈的底部。如果你向next()传递了一个error,而你并没有在错误处理句柄中处理这个error,Express内置的缺省错误处理句柄就是最后兜底的)。假如我们想手动控制返回的错误内容,则需要加载一个自定义错误处理的中间件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var express = require('express');
var app = express();

app.use(function(req, res, next) {
console.log('1');
next(new Error('haha'));
});

app.use(function(req, res, next) {
console.log('2');
res.status(200).end();
});

//错误处理
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!'); //500状态一样可以response文本内容
});

app.listen(3000);
// Notice that when not calling “next” in an error-handling function, you are responsible for writing (and ending) the response. Otherwise those requests will “hang” and will not be eligible for garbage collection.

15、如果向next()传入参数(除了‘route’字符串),Express会认为当前请求有错误的输出,因此跳过后续其他非错误处理和路由/中间件函数。如果需做特殊处理,需要创建新的错误处理路由,如下所示。如果路由句柄有多个回调函数,可使用‘route’参数跳到下一个路由句柄。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
app.get('/a_route_behind_paywall', 
function checkIfPaidSubscriber(req, res, next) {
if(!req.user.hasPaid) {
// 继续处理该请求
next('route');
}
}, function getPaidContent(req, res, next) {
PaidContent.find(function(err, doc) {
if(err) return next(err);
res.json(doc);
});
});
//在这个例子中,句柄getPaidContent会被跳过,但app中为/a_route_behind_paywall定义的其他句柄则会继续执行。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 //Dispatch a req, res into the router.
function next(err) {
var layerError = err === 'route'? null: err;

.....省略

while (match !== true && idx < stack.length) {
layer = stack[idx++]; //中间件堆栈
match = matchLayer(layer, path);
route = layer.route;

if (typeof match !== 'boolean') {
// hold on to layerError
layerError = layerError || match;
}

if (match !== true) {
continue;
}

if (!route) {
// process non-route handlers normally
continue;
}

if (layerError) {
// routes do not match with a pending error
match = false;
continue;
}

var method = req.method;
var has_method = route._handles_method(method);

// build up automatic options response
if (!has_method && method === 'OPTIONS') {
appendMethods(options, route._options());
}

// don't even bother matching route
if (!has_method && method !== 'HEAD') {
match = false;
continue;
}
}

.....省略

if (layerError) {
layer.handle_error(layerError, req, res, next);
} else {
layer.handle_request(req, res, next);
}
}

//Handle the request for the layer.
Layer.prototype.handle_request = function handle(req, res, next) {
var fn = this.handle;

if (fn.length > 3) {

// not a standard request handler
return next();
}

try {
fn(req, res, next);
} catch (err) {
next(err);
}
};

//Handle the error for the layer
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
var fn = this.handle;

if (fn.length !== 4) {
// not a standard error handler
return next(error);
}

try {
fn(error, req, res, next);
} catch (err) {
next(err);
}
};

16、注意:中间件的加载顺序很重要!比如:通常把日志中间件放到比较靠前的位置,后面将会介绍的connect-flash中间件是基于session的,所以需要在express-session后加载。
16、express项目目录结构:

对应文件及文件夹的用处:
a、models: 存放操作数据库的文件。
b、public: 存放静态文件,如样式、图片等。
c、routes: 存放路由文件。
d、views: 存放模板文件。
e、index.js: 程序主文件。
f、package.json: 存储项目名、描述、作者、依赖等等信息。
17、npm i config-lite connect-flash connect-mongo ejs express express-formidable express-session marked moment mongolass objectid-to-timestamp sha1 winston express-winston –save

18、Express:url占位符:xxx—req.params.xxx;get请求—req.query;post请求—经过body-parser中间件—req.body;文件上传请求—经过multer中间件(用于处理enctype=”multipart/form-data”(设置表单的MIME编码)的表单数据)—req.files[0];cookie获取—经过cookie-parser中间件—req.cookies。
19、不管是小项目还是大项目,将配置与代码分离是一个非常好的做法。我们通常将配置写到一个配置文件里,如 config.js 或 config.json ,并放到项目的根目录下。但通常我们都会有许多环境,如本地开发环境、测试环境和线上环境等,不同的环境的配置不同,我们不可能每次部署时都要去修改引用 config.test.js 或者 config.production.js。config-lite 是一个轻量的读取配置文件的模块。config-lite 会根据环境变量(NODE_ENV)的不同从当前执行进程目录下的 config 目录加载不同的配置文件。如果不设置 NODE_ENV,则读取默认的 default 配置文件,如果设置了 NODE_ENV,则会合并指定的配置文件和 default 配置文件作为配置,config-lite 支持 .js、.json、.node、.yml、.yaml 后缀的文件。如果程序以 NODE_ENV=test node app 启动,则通过 require(‘config-lite’) 会依次降级查找 config/test.js、config/test.json、config/test.node、config/test.yml、config/test.yaml 并合并 default 配置; 如果程序以 NODE_ENV=production node app 启动,则通过 require(‘config-lite’) 会依次降级查找 config/production.js、config/production.json、config/production.node、config/production.yml、config/production.yaml 并合并 default 配置。
20、由于我们博客页面是后端渲染的,所以只通过简单的 (GET) 和

(POST) 与后端进行交互。
21、我们通过引入 express-session 中间件实现对会话的支持:app.use(session(options))。session 中间件会在 req 上添加 session 对象,即 req.session 初始值为 {},当我们登录后设置 req.session.user = 用户信息,返回浏览器的头信息中会带上 set-cookie 将 session id 写到浏览器 cookie 中,那么该用户下次请求时,通过带上来的 cookie 中的 session id 我们就可以查找到该用户,并将用户信息保存到 req.session.user。
22、connect-flash 是基于 session 实现的,它的原理很简单:设置初始值 req.session.flash={},通过 req.flash(name, value) 设置这个对象下的字段和值,通过 req.flash(name) 获取这个对象下的值,同时删除这个字段。
23、我们可以把用户状态的检查封装成一个中间件,在每个需要权限控制的路由加载该中间件,即可实现页面的权限控制。
24、注意:中间件的加载顺序很重要。如上面设置静态文件目录的中间件应该放到 routes(app) 之前加载,这样静态文件的请求就不会落到业务逻辑的路由里;flash 中间件应该放到 session 中间件之后加载,因为 flash 是基于 session 的。
25、app.get(path, callback [, callback …]):You can provide multiple callback functions that behave just like middleware, except these callbacks can invoke next(‘route’) to bypass the remaining route callback(s). You can use this mechanism to impose pre-conditions on a route, then pass control to subsequent routes if there’s no reason to proceed with the current route.
26、express 中有两个对象可用于模板的渲染:app.locals 和 res.locals。上面的模板中我们用到了 blog、user、success、error 变量,我们将 blog 变量挂载到 app.locals 下,将 user、success、error 挂载到 res.locals 下。可以看出:在调用 res.render 的时候,express 合并(merge)了 3 处的结果后传入要渲染的模板,优先级:res.render 传入的对象> res.locals 对象 > app.locals 对象,所以 app.locals 和 res.locals 几乎没有区别,都用来渲染模板,使用上的区别在于:app.locals 上通常挂载常量信息(如博客名、描述、作者信息),res.locals 上通常挂载变量信息,即每次请求可能的值都不一样(如请求者信息,res.locals.user = req.session.user)。
1
2
3
4
5
6
7
8
9
10
11
 // express/lib/response.js
res.render = function render(view, options, callback) {
var app = this.req.app;
var opts = options || {};
...
// merge res.locals
opts._locals = self.locals;
...
// render
app.render(view, opts, done);
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// express/lib/application.js	
app.render = function render(name, options, callback) {
...
var opts = options;
var renderOptions = {};
...
// 1、merge app.locals
merge(renderOptions, this.locals);

// 2、merge options._locals
if (opts._locals) {
merge(renderOptions, opts._locals);
}

// 3、merge options
merge(renderOptions, opts);
...
tryRender(view, renderOptions, done);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
// 设置模板全局常量
app.locals.blog = {
title: pkg.name,
description: pkg.description
};

// 添加模板必需的三个变量
app.use(function (req, res, next) {
res.locals.user = req.session.user;
res.locals.success = req.flash('success').toString();
res.locals.error = req.flash('error').toString();
next();
});

27、我们使用express-formidable处理form表单(包括文件上传)。Set-Cookie中的比较重要的属性:secure:当secure值为true时,cookie在HTTP中是无效,在HTTPS中才有效,httpOnly:是微软对COOKIE做的扩展。如果在COOKIE中设置了“httpOnly”属性,则通过程序(JS脚本、applet等)将无法读取到COOKIE信息,防止XSS攻击产生。expires/Max-Age 字段为此cookie超时时间。若设置其值为一个时间,那么当到达此时间后,此cookie失效。不设置的话默认值是Session,意思是cookie会和session一起失效。当浏览器关闭(不是浏览器标签页,而是整个浏览器) 后,此cookie失效。express-session中的store选项表示session的存储方式,默认存放在内存中,也可以使用redis,mongodb等。express生态中都有相应模块的支持。
28、Express已经将Session管理的整个实现过程简化到仅仅几行代码的配置的地步了,你完全不用理解整个session产生、存储、返回、过期、再颁发的结构,使用Express和Redis实现Session管理,只要两个中间件就足够了:express-session、connect-redis。req在经过session中间件的时候就会自动完成session的有效性验证、过期/重新颁发、以及对session中数据的获取了。注销操作:在req.session上调用destroy()方法来清空session就可以了。
29、session.save():把session中的数据重新保存到store中,用内存的内容去替换掉store中的内容。这个方法在HTTP的响应后自动被调用。如果session中的数据被改变了(这个行为可以通过中间件的很多的配置来改变),正因为如此这个方法一般不用显示调用。但是在长连接的websocket中这个方法一般需要手动调用。session.touch():更新maxAge属性,一般不需要手动调用,因为session的中间件已经替你调用了。也就是把session的maxAge设置为构造Session对象的时候的初始值。
30、每一个路由都可以有一个或者多个处理器函数,当匹配到路由时,这个/些函数将被执行。路由的定义由如下结构组成:app.METHOD(PATH, HANDLER)。其中,app是一个express实例;METHOD是某个HTTP请求方式中的一个;PATH是服务器端的路径;HANDLER是当路由匹配到时需要执行的函数。
31、将静态资源文件所在的目录作为参数传递给express.static中间件就可以提供静态资源文件的访问了。例如,假设在public目录放置了图片、CSS和JavaScript文件,你就可以:app.use(express.static(‘public’));现在,public目录下面的文件就可以访问了。http://localhost:3000/images/kitten.jpg。所有文件的路径都是相对于存放目录的,因此,存放静态文件的目录名不会出现在URL中。如果你希望所有通过express.static访问的文件都存放在一个“虚拟(virtual)”目录(即目录根本不存在)下面,可以通过为静态资源目录指定一个挂载路径的方式来实现,如下所示:app.use(‘/static’, express.static(‘public’));现在,你就可以通过带有”/static”前缀的地址来访问public目录下面的文件了。http://localhost:3000/static/images/kitten.jpg。
32、Express支持任何符合(path, locals, callback)接口规范的模板引擎。通过app.engine(ext, callback)方法即可创建一个你自己的模板引擎。其中,ext指的是文件扩展名、callback是模板引擎的主函数,接受文件路径、参数对象和回调函数作为其参数。

1
2
3
4
5
6
7
8
9
10
11
12
var fs = require('fs');  //此模板引擎依赖fs模块
app.engine('ntl', function (filePath, options, callback) { //定义模板引擎
fs.readFile(filePath, function (err, content) {
if (err) return callback(new Error(err));
//这是一个功能极其简单的模板引擎
var rendered = content.toString().replace('#title#', '<title>'+ options.title +'</title>')
.replace('#message#', '<h1>'+ options.message +'</h1>');
return callback(null, rendered);
})
});
app.set('views', './views'); //指定视图所在的位置
app.set('view engine', 'ntl'); //注册模板引擎

33、如何处理404:在Express中,404并不是一个错误(error)。因此,错误处理器中间件并不捕获404。这是因为404只是意味着某些功能没有实现。也就是说,Express执行了所有中间件、路由之后还是没有获取到任何输出。你所需要做的就是在其所有他中间件的后面添加一个处理404的中间件。
34、如何设置一个错误处理器:错误处理器中间件的定义和其他中间件一样,唯一的区别是4个而不是3个参数,即(err, req, res, next):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// render the error page
res.status(err.status || 500);
res.render('error');
});

35、如何渲染纯HTML文件:不需要!无需通过res.render()渲染HTML。你可以通过res.sendFile()直接对外输出HTML文件。
36、通过Express应用生成器工具可以快速创建一个应用的骨架。通过如下命令安装:npm install express-generator -g。在当前工作目录下创建一个命名为myapp的应用:express myapp。Express 4应用生成器生成的app.js是一个Node模块,不能作为应用(除非修改代码)单独启动,需要通过一个Node文件加载并启动,这里这个文件就是node ./bin/www。创建或启动Express应用时,bin目录或者文件名没有后缀的www文件都不是必需的,它们只是生成器推荐的做法,请根据需要修改。通过Express应用生成器创建的应用一般都有如下目录结构:

37、在Express中,app.use把中间件加入一个栈中,http request将触发整个中间件链条,并依次执行(通过next()函数实现),功能类似于filter,但其作用却大于filter,它可以动态地给req,res添加内容。
38、路由句柄:可以为请求处理提供多个回调函数,其行为类似中间件。唯一的区别是这些回调函数有可能调用next(‘route’)方法而略过其他路由回调函数。可以利用该机制为路由定义前提条件,如果在现有路径上继续执行没有意义,则可将控制权交给剩下的路径。
39、响应对象(res)的方法向客户端返回响应,终结请求响应的循环。如果在路由句柄中一个方法也不调用,来自客户端的请求会一直挂起。
40、可使用express.Router类创建模块化、可挂载的路由句柄。Router实例是一个完整的中间件和路由系统,因此常称其为一个“mini-app”。
41、Express是一个自身功能极简,完全是由路由和中间件构成一个的web开发框架:从本质上来说,一个Express应用就是在调用各种中间件。中间件(Middleware)是一个函数,中间件的功能包括:a、执行任何代码。b、修改请求和响应对象。c、终结请求-响应循环。d、调用堆栈中的下一个中间件。如果当前中间件没有终结请求-响应循环,则必须调用next()方法将控制权交给下一个中间件,否则请求就会挂起。Express应用可使用如下几种中间件:应用级中间件;路由级中间件;错误处理中间件;内置中间件;第三方中间件。使用可选择挂载路径,可在应用级别或路由级别装载中间件。另外,你还可以同时装载一系列中间件函数,从而在一个挂载点上创建一个子中间件栈。
42、 app.use([path,] function [, function…]):Mounts the middleware function(s) at the path. If path is not specified, it defaults to “/”.
43、应用级中间件:应用级中间件绑定到app对象,使用app.use()和app.METHOD(),其中,METHOD是需要处理的HTTP请求的方法,例如GET、PUT、POST等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var app = express();

// 没有挂载路径的中间件,应用的每个请求都会执行该中间件
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});

// 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});

// 路由和句柄函数(中间件系统),处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});

44、如果需要在中间件栈中跳过剩余中间件,调用next(‘route’)方法将控制权交给下一个路由。注意:next(‘route’)只对使用app.VERB()或router.VERB()加载的中间件有效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 一个中间件栈,处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
// 如果 user id 为 0, 跳到下一个路由
if (req.params.id == 0) next('route');
// 否则将控制权交给栈中下一个中间件
else next(); //
}, function (req, res, next) {
// 渲染常规页面
res.render('regular');
});

// 处理 /user/:id, 渲染一个特殊页面
app.get('/user/:id', function (req, res, next) {
res.render('special');
});

45、路由级中间件:路由级中间件和应用级中间件一样,只是它绑定的对象为express.Router()。var router = express.Router();路由级使用router.use()或router.VERB()加载。
46、错误处理中间件:错误处理中间件有4个参数,定义错误处理中间件时必须使用这4个参数。即使不需要next对象,也必须在签名中声明它,否则中间件会被识别为一个常规中间件,不能处理错误。
47、内置中间件:从4.x版本开始,Express已经不再依赖Connect了。除了express.static,Express以前内置的中间件现在已经全部单独作为模块安装使用了。
48、第三方中间件:通过使用第三方中间件从而为Express应用增加更多功能。安装所需功能的node模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。
49、在Express中使用模板引擎,需要在应用中进行如下设置才能让Express渲染模板文件:a、views:放模板文件的目录,比如:app.set(‘views’, ‘./views’);b、view engine:设置模板引擎,比如:app.set(‘view engine’, ‘jade’)。
50、调试Express:Express内部使用debug模块记录路由匹配、使用到的中间件、应用模式以及请求-响应循环。debug有点像改装过的console.log,不同的是,您不需要在生产代码中注释掉debug。它会默认关闭,而且使用一个名为DEBUG的环境变量还可以打开。当应用收到请求时,能看到Express代码中打印出的日志。

51、X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP代理或者负载均衡服务器时才会添加该项。
52、app.route():app.route()方法可为路由路径创建链式路由句柄。由于路径在一个地方指定,会让路由更加模块化,也能减少代码冗余和拼写错误。

1
2
3
4
5
6
7
8
9
10
app.route('/book')
.get(function(req, res) {
res.send('Get a random book');
})
.post(function(req, res) {
res.send('Add a book');
})
.put(function(req, res) {
res.send('Update the book');
});

53、express.Router类是一个完整的中间件和路由系统。创建一个模块化的路由,并加载中间件,然后定义一些路由,并且在主应用中将其挂载到指定路径。
54、集成数据库:为Express应用添加连接数据库的能力,只需要加载相应数据库的Node.js驱动即可。
55、The order in which you define middleware with router.use() is very important. They are invoked sequentially, thus the order defines middleware precedence. For example, usually a logger is the very first middleware you would use, so every request is logged.

1
2
3
4
5
6
var logger = require('morgan');
router.use(logger());
router.use(express.static(__dirname + '/public'));
router.use(function(req, res){
res.send('Hello');
});

Now suppose you wanted to ignore logging requests for static files, but to continue logging routes and middleware defined after logger(). You would simply move static() above:

1
2
3
4
5
router.use(express.static(__dirname + '/public'));
router.use(logger());
router.use(function(req, res){
res.send('Hello');
});

56、为了跨机器安装得到一致的结果,Yarn需要比你配置在package.json中的依赖列表更多的信息。Yarn需要准确存储每个安装的依赖是哪个版本。为了做到这样,Yarn使用一个你项目根目录里的yarn.lock文件。
57、yarn global 是一个命令前缀,可用于 add、bin、list 和 remove 等命令。 它们的行为和他们的普通版本相同,只是它们用一个全局目录来存储包。
58、npm install 命令用来安装模块到node_modules目录。安装之前,npm install会先检查,node_modules目录之中是否已经存在指定模块。如果存在,就不再重新安装了,即使远程仓库已经有了一个新版本,也是如此。如果你希望,一个模块不管是否安装过,npm 都要强制重新安装,可以使用-f或–force参数。
59、如果想更新已安装模块,就要用到npm update命令。它会先到远程仓库查询最新版本,然后查询本地版本。如果本地版本不存在,或者远程版本较新,就会安装。到registry这个网址下载压缩包,在本地解压,就得到了模块的源码。
60、npm install或npm update命令,从registry下载压缩包之后,都存放在本地的缓存目录。(Registry代理服务)
61、用npm root -g 查看全局包安装的路径。查询本地或全局的命令。
62、

Comments

去留言
2017-02-22

⬆︎TOP