Node.js 从零开发 web server博客项目[express重构博客项目]
web server博客项目
- Node.js 从零开发 web server博客项目[项目介绍]
- Node.js 从零开发 web server博客项目[接口]
- Node.js 从零开发 web server博客项目[数据存储]
- Node.js 从零开发 web server博客项目[登录]
- Node.js 从零开发 web server博客项目[日志]
- Node.js 从零开发 web server博客项目[安全]
- Node.js 从零开发 web server博客项目[express重构博客项目]
- Node.js 从零开发 web server博客项目[koa2重构博客项目]
- Node.js 从零开发 web server博客项目[上线与配置]
文章目录
express 下载 , 安装和使用 , express 中间件机制
安装 ( 使用脚手架 express-generator )
- 安装脚手架工具
cnpm i express-generator -g
- 使用 express 脚手架创建项目
express blog-express
- 进入项目目录
cd blog-express
- 安装项目初始化所需要的插件
cnpm i
- 安装热更新插件与环境插件
cnpm i nodemon cross-env -D
- 修改相应的配置
- 在
package.json
增加script
项 :"dev": "cross-env NODE_ENV=dev nodemon ./bin/www"
- 启动项目
npm run dev
初始化代码介绍 , 处理路由
介绍 app.js
- 各个插件的作用
- 思考各个插件的实现原理
- 处理 get 请求和 post 请求
var createError = require('http-errors'); // 处理不存在或者错误的页面提供一个友好的提示
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser'); // 解析 cookie , 使用 req.cookies 访问 cookie
var logger = require('morgan'); // 日志功能
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup // 前端模板引擎
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev')); // 日志功能
app.use(express.json()); // 解析postdata中的json格式
app.use(express.urlencoded({ extended: false })); // 解析postdata中的from(x-www-form-urlencoded)格式
app.use(cookieParser());// 解析 cookie , 使用 req.cookies 访问 cookie
app.use(express.static(path.join(__dirname, 'public'))); //
// 处理路由
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler // 处理不存在或者错误的页面
app.use(function (req, res, next) {
next(createError(404));
});
// 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');
});
module.exports = app;
router/users.js
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
使用中间件
Writing middleware for use in Express apps
Using middleware
开发接口 , 连接数据库 , 实现登录 , 日志记录
初始化环境
- 安装插件 mysql xss
- mysql controller resModel 相关代码可以复用
- 初始化目录
express 开发接口
初始化项目 , 之前的部分代码可以复用
开发路由 , 实现登录
登录
使用 express-session 和 connect-redis , 简单方便
cnpm i express-session -S
app.js
var session = require('express-session')
...
app.use(session({
secret: 'keyboard cat',
cookie: {
path: '/',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000
}
}))
...
cnpm i redis connect-redis -S
db/redis.js
const redis = require('redis')
const { REDIS_CONF } = require('../conf/db.js')
// 创建客户端
const redisClient = redis.createClient(REDIS_CONF.port, REDIS_CONF.host)
redisClient.on('error', err => {
console.error(err)
})
module.exports = redisClient
使用
app.js
...
var RedisStore = require('connect-redis')(session)
var redisClient = require('./db/redis')
...
var sessionStore = new RedisStore({
client: redisClient
})
app.use(session({
secret: 'abcdefg',
cookie: {
path: '/',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000
},
store: sessionStore
}))
...
登录之后可查看到redis信息
express>redis-cli
127.0.0.1:6379> flushAll
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> keys *
1) "sess:QDTy6D6sLv-bFU9qxTOk_zqf9msMQ-jL"
127.0.0.1:6379> get sess:QDTy6D6sLv-bFU9qxTOk_zqf9msMQ-jL
"{\"cookie\":{\"originalMaxAge\":86400000,\"expires\":\"2019-07-12T10:52:47.777Z\",\"httpOnly\":true,\"path\":\"/\"}}"
127.0.0.1:6379> get sess:QDTy6D6sLv-bFU9qxTOk_zqf9msMQ-jL
// 登录后
"{\"cookie\":{\"originalMaxAge\":86400000,\"expires\":\"2019-07-12T10:54:54.582Z\",\"httpOnly\":true,\"path\":\"/\"},\"username\":\"zhangsan\",\"realname\":\"\xe5\xbc\xa0\xe4\xb8\x89\"}"
127.0.0.1:6379>
req.session 保存登录信息 , 登录校验做成 express 中间件
创建middleware/loginCheck.js
const { ErrorModel } = require('../model/resModel')
module.exports = (req, res, next) => {
if (req.session.username) {
next()
return
}
res.json(
new ErrorModel('未登录')
)
}
- 使用
router/blog.js
var express = require('express');
var router = express.Router();
const {
getList,
getDetail,
newBlog,
updateBlog,
delBlog
} = require('../controller/blog')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const loginCheck = require('../middleware/loginCheck')
/* GET users listing. */
router.get('/list', (req, res, next) => {
let author = req.query.author || ''
const keyword = req.query.keyword || ''
if (req.query.isadmin) {
// 管理员界面
if (req.session.username == null) {
// 未登录
res.json(
new ErrorModel('未登录')
)
return
}
// 强制查询自己的博客
author = req.session.username
}
const result = getList(author, keyword)
return result.then(listData => {
res.json(
new SuccessModel(listData)
)
})
});
// 获取博客详情
router.get('/detail', (req, res, next) => {
const result = getDetail(req.query.id)
return result.then(data => {
res.json(
new SuccessModel(data)
)
})
})
// 新建一篇博客
router.post('/new', loginCheck, (req, res, next) => {
req.body.author = req.session.username
const result = newBlog(req.body)
return result.then(data => {
res.json(
new SuccessModel(data)
)
})
})
// 更新一篇博客
router.post('/update', loginCheck, (req, res, next) => {
const result = updateBlog(req.query.id, req.body)
return result.then(val => {
if (val) {
res.json(
new SuccessModel()
)
} else {
res.json(
new ErrorModel('更新博客失败')
)
}
})
})
// 删除一篇博客
router.post('/del', (req, res, next) => {
const author = req.session.username
const result = delBlog(req.query.id, author)
return result.then(val => {
if (val) {
res.json(
new SuccessModel()
)
} else {
res.json(
new ErrorModel('删除博客失败')
)
}
})
})
module.exports = router;
记录日志
access log 记录 , 直接使用脚手架推荐的 Morgan
morgan
代码实现
package.json
"prd": "cross-env NODE_ENV=production nodemon ./bin/www"
app.js
const morgan = require('morgan');
const ENV = process.env.NODE_ENV
if (ENV !== 'production') {
// 开发环境 / 测试环境
app.use(morgan('dev'))
} else {
// 线上环境
const logFileName = path.join(__dirname, 'logs', 'access.log')
const writeStream = fs.createWriteStream(logFileName, {
flags: 'a'
})
app.use(morgan('combined'), {
stream: writeStream
})
}
自定义日志使用 console.log 和 console.error 即可
- 上线与配置会讲到
日志文件拆分 , 日志内容分析 ,
- 见上章节
分析 express 中间件原理
分析如何实现
- app.use 用来注册中间件 , 先收集起来
- 遇到 http 请求 , 会根据 path 和 method 判断出发那些
- 实现 next 机制 , 即上一个通过 next 触发下一个
代码演示
middleware-express
const http = require('http')
const slice = Array.prototype.slice
class LikeExpress {
constructor() {
// 存放中间件的列表
this.routes = {
all: [], // app.use(...)
get: [], // app.get(...)
post: [] // app.post(...)
}
}
register(path) {
const info = {}
if (typeof path === 'string') {
info.path = path
// 从第二个参数开始,转换为数组,存入 stack
info.stack = slice.call(arguments, 1)
} else {
info.path = '/'
// 从第一个参数开始,转换为数组,存入 stack
info.stack = slice.call(arguments, 0)
}
return info
}
use() {
const info = this.register.apply(this, arguments)
this.routes.all.push(info)
}
get() {
const info = this.register.apply(this, arguments)
this.routes.get.push(info)
}
post() {
const info = this.register.apply(this, arguments)
this.routes.post.push(info)
}
match(method, url) {
let stack = []
if (url === '/favicon.ico') {
return stack
}
// 获取 routes
let curRoutes = []
curRoutes = curRoutes.concat(this.routes.all)
curRoutes = curRoutes.concat(this.routes[method])
curRoutes.forEach(routeInfo => {
if (url.indexOf(routeInfo.path) === 0) {
// url === '/api/get-cookie' 且 routeInfo.path === '/'
// url === '/api/get-cookie' 且 routeInfo.path === '/api'
// url === '/api/get-cookie' 且 routeInfo.path === '/api/get-cookie'
stack = stack.concat(routeInfo.stack)
}
})
return stack
}
// 核心的 next 机制
handle(req, res, stack) {
const next = () => {
// 拿到第一个匹配的中间件
const middleware = stack.shift()
if (middleware) {
// 执行中间件函数
middleware(req, res, next)
}
}
next()
}
callback() {
return (req, res) => {
res.json = (data) => {
res.setHeader('Content-type', 'application/json')
res.end(
JSON.stringify(data)
)
}
const url = req.url
const method = req.method.toLowerCase()
const resultList = this.match(method, url)
this.handle(req, res, resultList)
}
}
listen(...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
// 工厂函数
module.exports = () => {
return new LikeExpress()
}
Node.js 从零开发 web server博客项目[express重构博客项目]的更多相关文章
- Node.js 从零开发 web server博客项目[数据存储]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[koa2重构博客项目]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[安全]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[日志]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[登录]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[接口]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[项目介绍]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- node.js之十大Web框架
之前接触过Node.js是因为好奇大前端越来越能干了,连我后台的饭碗都要抢了,太嚣张了,于是我想打压打压它,然后就这样接触它了.再到后来是因为Settings-Sync插件二次开发,我需要用node. ...
- Node.js 安装与开发
Node.js 简介 Node.js是一个Javascript运行环境(runtime),发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装.Node.js对一些 ...
随机推荐
- GitHub 热点速览 Vol.33:听说程序员都是颜控?
作者:HelloGitHub-小鱼干 摘要:GitHub上面除了很多有趣的项目,也有很多高颜值的项目,比如:图片共享网站 Unsplash 开源的 Dataset,提供了两百多张高颜值美照.Heroi ...
- TCP协议中的三次握手和四次挥手(图解)-转
转自:http://blog.csdn.net/whuslei/article/details/6667471/ 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看 ...
- 第5章 JDBC/ODBC服务器
第5章 JDBC/ODBC服务器 Spark SQL也提供JDBC连接支持,这对于让商业智能(BI)工具连接到Spark集群上以 及在多用户间共享一个集群的场景都非常有用.JDBC 服务器作为一个独立 ...
- Python语言中的关键字(自己做的读书笔记)
电脑配置:联想笔记本电脑 windows8系统 Python版本:2.7.8 本文章撰写时间:2015.1.1 作者:陈东陈 阅读说明: 1.本文都是先解释,后放图片: 2.文中斜体部分要么为需要输入 ...
- .net core 中的经典设计模式的应用
.net core 中的经典设计模式的应用 Intro 前段时间我们介绍了23种设计模式,今天来分享一下 asp.net core 种我觉得比较典型的设计模式的应用 实例 责任链模式 asp.net ...
- Windows Server 2012 数据库定时备份
为了数据的安全,我们在服务器上设置了每周备份一次,下面是具体步骤: 一.在文件客户端服务器创建db_backup.cmd的Windows命令脚本.输入以下内容(直接复制可能出错,请手动输入): @ec ...
- Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContex
问题描述: 在idea中maven构建web项目,启动Tomcat插件时,出现Failed to start component [StandardEngine[Tomcat].StandardHos ...
- js区别对象和数组的三种方法
var arr = {}||[]; 区分arr是数组还是对象 1.arr.constructor ...
- React技术实践(1)
随着系统越来越庞大,前端也变得越来越复杂,因此,构建一套组件化的前端变得很重要了. 之前一直在使用Asp.net来进行前端的组件化,Asp.net组件化有个很大的缺陷,就是和后台代码绑定太紧密了,不符 ...
- 据说是最好的记忆工具——Anki
http://www.ankichina.net/ .u1s1,确实挺好用,自建题库,全程自助. 可以插入文字.图片.音频,会安排合理的复习频率,可以随时同步,电脑手机版本全.