https://github.com/nswbmw/N-blog/
1. 环境变量
环境变量(environment variables)
一般是指在操作系统中用来指定操作系统运行环境的一些参数。
简单来讲,环境变量就是传递参数给运行程序的。
env //显示环境变量
nodejs使用
1 | NODE_ENV=test node app |
debug模块使用
1 | DEBUG=* node app |
Run scripts that set and use environment variables across platforms
1 | cross-env NODE_ENV=test node app |
2. package.json
https://docs.npmjs.com/files/package.json
语义化版本(semver)
即 dependencies、devDependencies 和 peerDependencies 里的如:"co": "^4.6.0"
。
semver 格式:主版本号.次版本号.修订号
。版本号递增规则如下:
主版本号
:做了不兼容的 API 修改次版本号
:做了向下兼容的功能性新增修订号
:做了向下兼容的 bug 修正
3. npm操作
搜索npm模块
1. npm init
初始化一个空项目
2. npm install
1 | $ npm install -h |
直接使用 npm i
安装的模块是不会写入 package.json
的 dependencies (或 devDependencies),需要额外加个参数:
npm i express --save
/npm i express -S
(安装 express,同时将"express": "^4.14.0"
写入 dependencies )
npm i express --save-dev
/npm i express -D
(安装 express,同时将"express": "^4.14.0"
写入 devDependencies )
npm i express --save --save-exact
(安装 express,同时将固定版本号"express": "4.14.0"
写入 dependencies )
1 | npm config set save-exact true |
这样每次 npm i xxx --save
的时候会锁定依赖的版本号,相当于加了 --save-exact
参数。(npm config set
命令将配置写到了 ~/.npmrc
文件,运行 npm config list
查看。)
3. npm scripts
npm start
等价于npm run start
npm test
等价于 npm run test
4. npm shrinkwrap
运行后会在当前目录下产生一个 npm-shrinkwrap.json
,里面包含了通过 node_modules
计算出的模块的依赖树及版本。
只要目录下有 npm-shrinkwrap.json
则运行 npm install
的时候会优先使用 npm-shrinkwrap.json
进行安装,没有则使用 package.json
进行安装。
npm shrinkwrap
只会生成 dependencies 的依赖,不会生成 devDependencies 的。
4. 初始化express项目
npm init
npm i express --save
1 | //index.js |
运行 node index
,打开浏览器访问 localhost:3000
时,页面应显示 hello, express
。
5. node-supervisor
A little supervisor script for nodejs. It runs your program, and watches for code changes, so you can have hot-code reloading-ish behavior, without worrying about memory leaks and making sure you clean up all the inter-module references, and without a whole new require system.
1 | npm i -g supervisor |
运行 supervisor index
启动程序, supervisor 会监听当前目录下 node 和 js 后缀的文件,当这些文件发生改动时,supervisor 会自动重启程序。
6. 路由匹配
Turn a path string such as /user/:name into a regular expression.
express 使用了 path-to-regexp
模块实现的路由匹配。
1 | app.get('/users/:name', function (req, res) { |
req 包含了请求来的相关信息,res 则用来返回该请求的响应。
常用的 req 的属性:
req.query:
解析 url 中的querystring
,如 ?name=haha
,req.query 的值为 {name: 'haha'}
req.params:
解析 url 中的占位符,如 /:name
,访问 /haha
,req.params 的值为 {name: 'haha'}
req.body:
解析后请求体,需使用相关的模块,如 body-parser
,请求体为 {"name": "haha"}
,则 req.body 为 {name: 'haha'}
express.Router
创建空文件夹 routes,在 routes 目录下创建 index.js 和 users.js。最后代码如下:
index.js
1 | const express = require('express') |
routes/index.js
1 | const express = require('express') |
routes/users.js
1 | const express = require('express') |
以上代码的意思是:我们将 /
和 /users/:name
的路由分别放到了 routes/index.js 和 routes/users.js 中,每个路由文件通过生成一个 express.Router 实例 router 并导出,通过 app.use
挂载到不同的路径。这两种代码实现了相同的功能,但在实际开发中推荐使用 express.Router 将不同的路由分离到不同的路由文件中。
7. 模板引擎ejs
1 | npm i ejs --save |
index.js
1 | const path = require('path') |
通过 app.set
设置模板引擎为 ejs 和存放模板的目录。
在 myblog 下新建 views 文件夹,在 views 下新建 users.ejs
,添加如下代码:
views/users.ejs
1 |
|
routes/users.js
1 | const express = require('express') |
通过调用 res.render
函数渲染 ejs 模板。
res.render
第一个参数是模板的名字,这里是 users
则会匹配 views/users.ejs
,第二个参数是传给模板的数据,这里传入 name
,则在 ejs 模板中可使用 name
。
res.render
的作用就是将模板和数据结合生成 html,同时设置响应头中的 Content-Type: text/html
,告诉浏览器我返回的是 html,不是纯文本,要按 html 展示。
ejs 3 种常用标签:
<% code %>
:运行 JavaScript 代码,不输出<%= code %>
:显示转义后的 HTML内容<%- code %>
:显示原始 HTML 内容
<%= code %>
和 <%- code %>
都可以是 JavaScript 表达式生成的字符串。
当变量 code
为普通字符串时,两者没有区别。
当 code 比如为 <h1>hello</h1>
这种字符串时,<%= code %>
会原样输出 <h1>hello</h1>
,而 <%- code %>
则会显示 H1 大的 hello 字符串。
拆分模板组件
- 模板可复用,减少重复代码
- 主模板结构清晰
views/header.ejs
1 |
|
views/footer.ejs
1 | </body> |
views/users.ejs
在 users.ejs
通过 ejs 内置的 include
方法引入header.ejs
和 footer.ejs
(要用 <%- include('header') %>
而不是 <%= include('header') %>
)
1 | <%- include('header') %> |
8. 中间件
app.use([path,] callback [, callback…])
express 中的中间件(middleware)
就是用来处理请求的,当一个中间件处理完,可以通过调用 next()
传递给下一个中间件,如果没有调用 next()
,则请求不会往下传递,如内置的 res.render
其实就是渲染完 html 直接返回给客户端,没有调用 next()
,从而没有传递给下一个中间件。
1 | const express = require('express') |
通过 app.use
加载中间件,在中间件中通过 next
将请求传递到下一个中间件,next
可接受一个参数接收错误信息,如果使用了 next(error)
,则会返回错误而不会传递到下一个中间件。
中间件的加载顺序很重要。
1 | const express = require('express') |
错误处理
express 内置了一个默认的错误处理器,假如我们想手动控制返回的错误内容,则需要加载一个自定义错误处理的中间件。
1 | //index.js |
9. 配置文件config-lite
A super simple & flexible & intuitive config module, support yaml & toml.
config-lite
是一个轻量的读取配置文件的模块。config-lite
会根据环境变量(NODE_ENV)
的不同加载 config 目录下不同的配置文件。如果不设置NODE_ENV
,则读取默认的 default 配置文件,如果设置了 NODE_ENV
,则会合并指定的配置文件和 default 配置文件作为配置,config-lite
支持 .js、.json、.node、.yml、.yaml
后缀的文件(依次降级查找并合并 default 配置)。
例子:如果程序以 NODE_ENV=production node app 启动,则 config-lite 会依次降级查找 config/production.js、config/production.json、config/production.node、config/production.yml、config/production.yaml 并合并 default 配置。
10. 会话
由于 HTTP 协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是会话(Session)
。
cookie 与 session 的区别
- cookie 存储在浏览器(有大小限制),session 存储在服务端(没有大小限制)
- 通常 session 的实现是基于 cookie 的,session id 存储于 cookie 中 session 更安全,cookie可以直接在浏览器查看甚至编辑
- Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
- Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
express-session 中间件
引入中间件,实现对会话的支持.
1 | app.use(session(options)) |
session 中间件会在 req 上添加 session 对象,即 req.session
初始值为 {}
,当我们登录后设置 req.session.user = 用户信息
,返回浏览器的头信息中会带上 set-cookie
将 session id
写到浏览器 cookie 中,那么该用户下次请求时,通过带上来的 cookie 中的 session id
我们就可以查找到该用户,并将用户信息保存到 req.session.user
。
connect-flash中间件
引入中间件,实现页面通知只显示一次,刷新后消失。
1 | npm install connect-flash |
The flash is a special area of the session used for storing messages. Messages are written to the flash and cleared after being displayed to the user. The flash is typically used in combination with redirects, ensuring that the message is available to the next page that is to be rendered.
它是基于 session 实现的,设置初始值 req.session.flash={}
,通过 req.flash(name, value)
设置这个对象下的字段和值,通过 req.flash(name)
获取这个对象下的值,同时删除这个字段,实现了只显示一次刷新后消失的功能。
express-session、connect-mongo 和 connect-flash 的区别与联系
express-session: 会话(session)支持中间件
connect-mongo: 将 session 存储于 mongodb,需结合 express-session 使用,我们也可以将 session 存储于 redis,如 connect-redis
connect-flash: 基于 session 实现的用于通知功能的中间件,需结合 express-session 使用
11. objectid-to-timestamp
addCreatedAt 自定义插件(通过 _id 生成时间戳)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21lib/mongo.js
------------
const moment = require('moment')
const objectIdToTimestamp = require('objectid-to-timestamp')
// 根据 id 生成创建时间 created_at
mongolass.plugin('addCreatedAt', {
afterFind: function (results) {
results.forEach(function (item) {
item.created_at = moment(objectIdToTimestamp(item._id)).format('YYYY-MM-DD HH:mm')
})
return results
},
afterFindOne: function (result) {
if (result) {
result.created_at = moment(objectIdToTimestamp(result._id)).format('YYYY-MM-DD HH:mm')
}
return result
}
})
24 位长的 ObjectId 前 4 个字节是精确到秒的时间戳,所以我们没有额外的存创建时间(如: createdAt)的字段。
ObjectId 生成规则