安装
官网下载安装 node官网:nodejs.cn/download/
介绍
- Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
- Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型。Node 是一个让 JavaScript 运行在服务端的开发平台
- 需要遵守ECMANScript语法
server开发和前端开发的区别
- 服务器稳定性
- 考虑内存和cpu
- 日志记录
- 安全性
nodejs基础语法介绍
http
http.createServer([options][, requestListener])
fs(文件系统)
fs.readFile读取文件
fs.readFile('文件', (err, data) => {
if (err) throw err;
console.log(data);
});
path(路径)
path.join()
使用平台特定的分隔符作为定界符将所有给定的 path 片段连接在一起,然后规范化生成的路径。零长度的 path 片段会被忽略。 如果连接的路径字符串是零长度的字符串,则返回 '.',表示当前工作目录。
path.resolve()
将路径或路径片段的序列解析为绝对路径。
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'
path.resolve('/foo/bar', '/tmp/file/');
// 返回: '/tmp/file'
path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');
// 如果当前工作目录是 /home/myself/node,
// 则返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'
stream
Writable - 可写入数据的流(例如 fs.createWriteStream())
Readable - 可读取数据的流(例如 fs.createReadStream()
全局对象process
process 对象是一个全局变量,它提供有关当前 Node.js 进程的信息并对其进行控制。 作为一个全局变量,它始终可供 Node.js 应用程序使用,无需使用 require()。
流对象
process.stdin
process.stdout
process.stderr
博客需求分析
开发一个博客系统,用户可登录,查看所有博客列表,对自己的博客内容增删改查。项目采用前后端分离方式开发。server端和前端
博客系统
- 登录功能
- 博客列表
- 当前用户博客列表
- 新增博客、编辑博客、删除博客
技术分析
表
用户信息表 | user
| id | account | password | realname |
|---|---|---|---|
| 1 | alis | 123 | 爱丽丝 |
| 2 | bob | 123 | 鲍勃 |
博客表 | blog
| id | title | content | text | author | userid | createtime | updatetime |
|---|---|---|---|---|---|---|---|
| 1 | title | content | text | 爱丽丝 | 1 | 1587977866756 | 1587977866234 |
| 2 | title | content | text | 鲍勃 | 2 | 15879778667343 | 1587977866764 |
接口设计
| 描述 | 接口 | 方法 | 参数 |
|---|---|---|---|
| 用户登录 | /api/user/login | POST | username、password |
| 用户登出 | /api/user/logout | POST |
| 描述 | 接口 | 方法 | 参数 |
|---|---|---|---|
| 获取博客列表 | /api/blog/list | GET | author、keyword |
| 获取博客详情 | /api/blog/detail | GET | id |
| 新增博客 | /api/blog/new | POST | title、content 、text |
| 更新博客 | /api/blog/update | POST | id、title、content 、text |
| 删除博客 | /api/blog/delete | POST | id |
数据存储
使用mysql数据库进行数据存储
mysql安装
安装地址:dev.mysql.com/downloads/m…
安装的过程中需要输入root密码。需记住密码。
安装可视化工具navicat/workbench安装
navicat安装地址:xclient.pipipan.com/fs/13114864…
解压密码:xclient.info
安装地址:dev.mysql.com/downloads/w…
安装完成之后,建库,建表,表操作。
MySQL的数据类型
主要包括以下五大类:
整数类型:BIT、BOOL、TINY INT、SMALL INT、MEDIUM INT、 INT、 BIG INT
浮点数类型:FLOAT、DOUBLE、DECIMAL
字符串类型:CHAR、VARCHAR、TINY TEXT、TEXT、MEDIUM TEXT、LONGTEXT、TINY BLOB、BLOB、MEDIUM BLOB、LONG BLOB
日期类型:Date、DateTime、TimeStamp、Time、Year
其他数据类型:BINARY、VARBINARY、ENUM、SET、Geometry、Point、MultiPoint、LineString、MultiLineString、Polygon、GeometryCollection等
数据类型的属性
| MySQL关键字 | 含义 |
|---|---|
| NULL | 数据列可包含NULL值 |
| NOT NULL | 数据列不允许包含NULL值 |
| DEFAULT | 默认值 |
| PRIMARY KEY | 主键 |
| AUTO_INCREMENT | 自动递增,适用于整数类型 |
| UNSIGNED | 无符号 |
| CHARACTER SET name | 指定一个字符集 |
sql基本语句
show databases;
create schema blogs;
use blogs;
-- show tables;
create table `user` (
`id` int not null auto_increment,
`username` varchar(25) not null,
`realname` varchar(25) not null,
`password` varchar(20) not null,
primary key (`id`)
)
insert into user (username,`password`,realname) values ('alis','123','爱丽丝')
insert into user (username,`password`,realname) values ('bob','123','鲍勃')
select * from user
select * from user where username like 'alis' order by id desc
update user set username='amanda' where id=1
delete from user where id=5
create table `blog` (
`id` int not null auto_increment,
`uid` varchar(20) not null,
`author` varchar(20) not null,
`title` varchar(50) not null,
`content` longtext not null,
`text` longtext not null,
`createtime` varchar(20) not null,
`updatetime` varchar(20),
primary key (`id`)
)
insert into blog (uid,author,title,content,text,createtime) values (1,'amanda','title','content','text',1588915947198)
set SQL_SAFE_UPDATES=0;// 安全模式开关
如何连接数据库
npm i -S mysql
const mysql = require('mysql')
// 创建链接对象
const con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '*****',
port: '3306',
database: 'blogs'
})
// 开始连接
con.connect()
// 执行 sql 语句
const sql = `select * from user`
con.query(sql, (err, result) => {
if (err) {
console.error(err)
return
}
console.log(result)
})
// 关闭连接
con.end()
cookie&&session
在cookie中存储uid,redis存储对应的userinfo
cookie
存储在浏览器的一段字符串(最大5kb),跨域不共享,每次发送http请求,讲请求域的cookie一起发送给server端,server可以修改cookie并且返回给浏览器,浏览器也可以通过javascript修改cookie
session
session存储userinfo,多进程无法共享。内存有限,访问量过大会有问题。
- 访问频繁,对性能要求高
- 可以不需要考虑断电丢失的问题
- 数据量不会很大
redis
特点:
- 缓存数据库
- 数据存储在内存中
- 相比mysql访问速度更快(内存和硬盘的区别)
- 成本高,存储数据量小
redis安装
windows:www.runoob.com/redis/redis…
mac: brew install redis
安装完成之后运行
redis-server
redis-cli
redis常用操作命令
key *
set
get
del
如何连接redis
npm i -S redis
const redis = require('redis')
// 创建客户端
const redisClient = redis.createClient(6379, '127.0.0.1')
redisClient.on('error', err => {
console.error(err)
})
// 测试
redisClient.set('myname', 'alis', redis.print)
redisClient.get('myname', (err, val) => {
if (err) {
console.error(err)
return
}
console.log('val ', val)
// 退出
redisClient.quit()
})
rendis-server启动后可拿到端口信息
数据库连接配置
Node.js ORM 框架 sequelize
安全
sql注入
使用mysql的escape解决sql注入问题
比如用户在登录的时候恶意输入用户名为alis --,导致拼接sql之后后面的语句不执行,直接登录
use blogs;
select * from user
where username='alis';delete from blog;
const author = escape(userData.title)
const password = escape(userData.password)
const sql = `
select * from user
where username=${author} password=${password};
`
xss攻击
比如用户在新建博客的时候,输入,如果按照原样存储则会窃取到用户的隐私cookie
解决办法,使用xss插件
拼接sql的时候,先把参数通过xss处理。
如xss(title)
将如<>(尖括号)、”(引号)、 ‘(单引号)、%(百分比符号)、;(分号)、()(括号)、&(& 符号)、+(加号)等进行转义。
密码加密
crypto 模块提供了加密功能
npm i -S crypto
const crypto = require('crypto')
// 密匙
const SECRET_KEY = '*********'
// md5 加密
function md5(content) {
let md5 = crypto.createHash('md5')
return md5.update(content).digest('hex')
}
// 加密函数
function genPassword(password) {
const str = `password=${password}&key=${SECRET_KEY}`
return md5(str)
}
module.exports = {
genPassword
}
接口开发
使用express-generator脚手架开发,express是nodeJs开发最常用的webserver 框架
全局安装脚手架
npm i -g express-generator
express express-test
npm i
npm start
脚手架初始化后内容介绍
public/views //可忽略是用来写前端代码的,前后端不分离开发使用
bin/www //启动node服务
routers //路由
app.js //注册中间件
app.js代码分析
var createError = require('http-errors'); //处理异常,如404
var express = require('express');// cookie处理,注册后,可以通过req.cookies访问cookie
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');// 日志插件
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express(); //通过express初始化app
app.use(logger('dev'));// 注册日志
app.use(express.json());// 处理postdata
app.use(express.urlencoded({ extended: false })); //表单数据处理
app.use(cookieParser());
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;
处理post旧的处理办法
let postData = ''
req.on('data', chunk => {
postData += chunk.toString()
})
req.on('end', () => {
if (postData) {
resolve(JSON.parse(postData))
return
}
resolve({})
})
morgan的日志配置可参考网址:github.com/expressjs/m…
dev::method :url :status :response-time ms - :res[content-length]
combined::remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
crontab定时任务配置
crontab -e //进行定时任务编辑部署
* * * * * sh path//crontab命令格式 分 时 日 月 周
* 0 * * * sh /Users/wangxin/Documents/share/nodejs/blog-express/logs
nodemon和pm2
测试环境使用nodemon正式环境使用pm2启动项目
pm2.conf.json
{
"apps": {
"name": "pm2-server",// 项目名
"script": "./bin/www",// 执行文件
"watch": true,// 是否监听文件变动然后重启
"ignore_watch": [
"node_modules",
"logs"
],
"instances": 4,// 应用启动实例个数
"error_file": "logs/err.log",// 错误日志文件
"out_file": "logs/out.log",// 日志文件
"log_date_format": "YYYY-MM-DD HH:mm:ss"// 指定日志文件的时间格式
}
}