简单概括以下几点:
1 | setTimeout(() => { |
require 这个文件得到的是空对象 {}
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 )第三种方式将固定版本号写入 dependencies,建议线上的 Node.js 应用都采取这种锁定版本号的方式,因为你不可能保证第三方模块下个小版本是没有验证 bug 的,即使是很流行的模块。
req 包含了请求来的相关信息,res 则用来返回该请求的响应,更多请查阅 express 官方文档。下面介绍几个常用的 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'}ejs 有 3 种常用标签:
<% code %>:运行 JavaScript 代码,不输出<%= code %>:显示转义后的 HTML内容<%- code %>:显示原始 HTML 内容注意:
<%= code %>和<%- code %>都可以是 JavaScript 表达式生成的字符串,当变量 code 为普通字符串时,两者没有区别。当 code 比如为<h1>hello</h1>这种字符串时,<%= code %>会原样输出<h1>hello</h1>,而<%- code %>则会显示 H1 大的 hello 字符串。
更多 ejs 的标签请看 官方文档。
小提示:拆分模板组件通常有两个好处:
- 模板可复用,减少重复代码
- 主模板结构清晰
注意:要用
<%- include('header') %>而不是<%= include('header') %>
models: 存放操作数据库的文件public: 存放静态文件,如样式、图片等routes: 存放路由文件views: 存放模板文件index.js: 程序主文件package.json: 存储项目名、描述、作者、依赖等等信息express: web 框架express-session: session 中间件connect-mongo: 将 session 存储于 mongodb,结合 express-session 使用connect-flash: 页面通知的中间件,基于 session 实现ejs: 模板express-formidable: 接收表单及文件上传的中间件config-lite: 读取配置文件marked: markdown 解析moment: 时间格式化mongolass: mongodb 驱动objectid-to-timestamp: 根据 ObjectId 生成时间戳sha1: sha1 加密,用于密码加密winston: 日志express-winston: express 的 winston 日志中间件config/default.js
1 | module.exports = { |
配置释义:
port: 程序启动要监听的端口号session: express-session 的配置信息,后面介绍mongodb: mongodb 的地址,以 mongodb:// 协议开头,myblog 为 db 名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 启动,则 config-lite 会依次降级查找 config/test.js、config/test.json、config/test.node、config/test.yml、config/test.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 配置。
config-lite 还支持冒泡查找配置,即从传入的路径开始,从该目录不断往上一级目录查找 config 目录,直到找到或者到达根目录为止。
功能及路由设计如下:
GET /signupPOST /signupGET /signinPOST /signinGET /signoutGET /postsGET /posts?author=xxxGET /posts/:postIdGET /posts/createPOST /posts/createGET /posts/:postId/editPOST /posts/:postId/editGET /posts/:postId/removePOST /commentsGET /comments/:commentId/remove由于我们博客页面是后端渲染的,所以只通过简单的 <a>(GET) 和 <form>(POST) 与后端进行交互,如果使用 jQuery 或者其他前端框架(如 Angular、Vue、React 等等)可通过 Ajax 与后端交互,则 api 的设计应尽量遵循 Restful 风格。
更多阅读:
由于 HTTP 协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是会话(Session)。
cookie 与 session 的区别
更多 session 的资料,参考:https://www.zhihu.com/question/19786827
我们通过引入 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 中间件实现这个功能。
connect-flash 是基于 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-redisconnect-flash: 基于 session 实现的用于通知功能的中间件,需结合 express-session 使用不管是论坛还是博客网站,我们没有登录的话只能浏览,登陆后才能发帖或写文章,即使登录了你也不能修改或删除其他人的文章,这就是权限控制。我们也来给博客添加权限控制,如何实现页面的权限控制呢?我们可以把用户状态的检查封装成一个中间件,在每个需要权限控制的路由加载该中间件,即可实现页面的权限控制。
可以看出:
checkLogin: 当用户信息(req.session.user)不存在,即认为用户没有登录,则跳转到登录页,同时显示 未登录 的通知,用于需要用户登录才能操作的页面checkNotLogin: 当用户信息(req.session.user)存在,即认为用户已经登录,则跳转到之前的页面,同时显示 已登录 的通知,如已登录用户就禁止访问登录、注册页面注意:中间件的加载顺序很重要。如上面设置静态文件目录的中间件应该放到 routes(app) 之前加载,这样静态文件的请求就不会落到业务逻辑的路由里;flash 中间件应该放到 session 中间件之后加载,因为 flash 是基于 session 实现的。
上面的 ejs 模板中我们用到了 blog、user、success、error 变量,我们将 blog 变量挂载到 app.locals 下,将 user、success、error 挂载到 res.locals 下。为什么要这么做呢?app.locals 和 res.locals 是什么?它们有什么区别?
express 中有两个对象可用于模板的渲染:app.locals 和 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)。
这里使用的是 mongolass
我们使用 express-formidable 处理表单的上传,表单普通字段挂载到 req.fields 上,表单上传后的文件挂载到 req.files 上,文件存储在 public/img 目录下。然后校验了参数,校验通过后将用户信息插入到 MongoDB 中,成功则跳转到主页并显示『注册成功』的通知,失败(如用户名被占用)则跳转回注册页面并显示『用户名已被占用』的通知。
注意:我们使用 sha1 加密用户的密码,sha1 并不是一种十分安全的加密方式,实际开发中可以使用更安全的 bcrypt或 scrypt 加密。 注意:注册失败时(参数校验失败或者存数据库时出错)删除已经上传到 public/img 目录下的头像。
bug - fs.unlink Callback must be a function v4.0注册时删除头像
1 | git checkout 版本号 # 切换学习时相应的版本 |
1 | 启动本地mongoDB数据库 |
fs.unlink Callback must be a function v4.0注册时删除头像
原文:https://www.cnblogs.com/lijianming180/p/12401861.html