使用Node开发后端项目

一、Node简单介绍

1、Node用途

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。

  1. 运行在服务器,作为web server
  2. 运行在本地,作为打包、构建工具

2、下载和安装

  1. 普通下载
    按照node官网下载即可。
  2. NVM下载

NVM是node的版本管理工具,可切换多个node版本。

window使用

github搜索 nvm-windows,按照步骤下载即可。

mac使用
  1. 打开你的Shell配置文件。如果你正在使用zsh,请打开 ~/.zshrc 文件。如果你正在使用bash,请打开 ~/.bashrc 文件。
  2. 在文件中添加以下代码:
1
2
bash复制代码export NVM_DIR="$HOME/.nvm"
[ -s "$(brew --prefix nvm)/nvm.sh" ] && . "$(brew --prefix nvm)/nvm.sh" # This loads nvm
  1. 保存并关闭文件。然后,在终端中输入以下命令,使更改生效:
1
2
bash复制代码source ~/.zshrc   # 如果你使用的是zsh
source ~/.bashrc # 如果你使用的是bash
命令介绍

使用NVM之前,需将之前已经独立安装的node版本卸载。后续都通过NMM管理node版本。

1
2
3
4
rust复制代码nvm list //查看已存在的node版本
nvm install 8.0.0 //安装node版本
nvm use 8.0.0 //切换node版本环境
nvm uninstall 8.0.0 //卸载

3、Node.js和JavaScript的区别

  1. JavaScirpt
    包括ECMAScript语法规范和Web API。
    两种结合,才能实现页面的各种操作。
    Javascript组成.png
  2. Node.js
    包括ECMAScript语法规范和Node.js API。
    两种结合,才能完成server端的任何操作。
    Node组成.png

4、Common.js 和debugger

5、 server端和前端的区别

server端的考虑点:

  • 服务稳定性
  • 考虑内存和CPU(优化,扩展)
  • 日志记录
  • 安全
  • 集群和服务拆分
  1. 服务稳定性
    server端可能会遭受各种恶意攻击或者误操作;
    PM2进场守候
  2. 考虑内存和CPU(优化,扩展)
    server端要承载很多请求,CPU和内存都是稀缺资源
    stream写日志,使用redis存session
  3. 日志记录
    server端要记录日志、存储日志、分析日志
  4. 安全
    越权操作,数据库攻击
    预防xss攻击和sql注入
  5. 集群和服务拆分
    通过扩展机器和服务拆分承载大流量

二、Node实现后端开发思路

使用node实现一个后台博客系统,简单的技术方案如下:

  • 数据如何存储
  • 如何与前端对接,即接口设计

三、Node.js的API介绍

1、http概述

一个http请求的整个过程:

  1. 前端:DNS解析,建立TCP连接(三次握手),发送http请求
  2. 后端:server接收到http请求,处理,并返回
  3. 前端:客户端接收到返回数据,处理数据(如渲染页面,执行js)

四、Node开发环境搭建

1、借助nodemoncorss-env

  • nodemon是一个工具,它可以在检测到目录中的文件更改时自动重新启动节点应用程序,从而帮助开发基于node.js的应用程序。
1
scss复制代码npm install --save-dev nodemon //安装

nodemon包装应用程序,因此您可以将通常传递给应用程序的所有参数传递给应用程序:

1
2
less复制代码// 配置文件
nodemon [your node app]
  • cross-env是一个跨平台运行设置和使用环境变量的脚本
1
2
3
4
5
6
7
8
json复制代码npm install --save-dev cross-env //安装

//配置文件
{
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
}
}

2、初始化路由

1.接口开发

  • 初始化路由:根据技术方案,设计出路由
  • 返回假数据:将路由和数据处理分离

五、登陆

1、cookie

  1. 什么是cookie
  • 存储在浏览器的一段字符串(最大5kb)
  • 跨域不共享
  • 格式如k1=k1;k2=k2;k3=k3;因此可以存储为结构化数据
  • 每次发送http亲求,会将请求域的cookie一起发给server
  • server可以修改cookie,并返回给浏览器
  • 浏览器中也可以通过JavaScript修改cookie(修改有限制)
  1. 客户端操作cookie
  • 查看cookie
  • 新增cookie (只能新增,不能修改)

cookie查看有三种方式:http请求/返回中;Application下;Console中执行document.cookie查看
cookie新增: 执行document.cookie = 'k2=200'
3. Server端操作cookie

  • 查看cookie
  • 修改cookie
  • 实现登陆验证
  1. 关于cookie的总结文字
  • 知道cookie的定义和特点;
  • 前后端如何查看和修改cookie;
  • 如何使用cookie实现登陆验证
  1. 缺点
    会暴露username,很危险

2、session

为什么使用session?

  • 原因:因为直接用cookie传值,会暴漏username等信息,很危险。
  • 解决办法:cookie中存储userid,server端对应username

使用session(session是一种登陆注册的通用解决方案),即server端存储用户信息
session解决方案.png

3、redis

  1. window下安装redis
    可参考安装步骤www.runoob.com/redis/redis…
1
2
bash复制代码redis-server.exe redis.windows.conf //window下启动redis
redis-cli.exe -h 127.0.0.1 -p 6379 //执行redis语句(set/get)

设置键值对:set myKey abc
取出键值对:get myKey

  1. 上一步的session使用的是js变量,放在node.js的进程内存中
    直接放到node.js进程中的缺陷:
  • 进程内存有限,访问量过大,内存暴增怎么办?
  • 正式线上运行时多进程,进程之间内存无法共享

进程内存模型.png
3. redis特点

  • webServer常用的缓存数据库,数据存放在内存中
  • 相比mysql,访问速度快(内存和硬盘不是一个级别的)
  • 成本高,可存储的数据量小
  1. redis和MySQL

4、nginx

  1. window下安装nginx
    可参考安装步骤nginx.org/en/download…
    nginx目录.png
  2. 修改conf/nginx.conf配置文件,设置代理指向
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ini复制代码server {
#*********nginx监听的端口在这里设置**********
listen 8088;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;

# *********这里是修改代理指向***********
#location / {
# root html;
# index index.html index.htm;
#}
location / {
proxy_pass http://localhost:8001;
}
location /api/ {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
}
}
  1. nginx 操作命令

window系统通过dos窗口,进入根目录,执行命令

1
2
makefile复制代码D:\soft\nginx>cd nginx-1.16.0
D:\soft\nginx\nginx-1.16.0>
  • 测试配置文件格式是否正确:nginx -t
  • 启动:nginx
  • 重启:nginx -s reload
  • 停止:nginx -s stop
  1. nginx启动报错,查看端口是否被占用
  • tasklist
    查看所有任务
  • 查看某个端口是否被监听的情况
1
2
3
4
yaml复制代码D:\soft\nginx\nginx-1.16.0>netstat -ano |findstr 8080
TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 15448 //被进程15448占用
TCP 10.200.22.57:55155 101.89.15.106:8080 ESTABLISHED 2088
TCP 10.200.22.57:55228 59.37.96.203:8080 ESTABLISHED 5812
  • 查看某个进程占用的具体程序是什么
1
2
arduino复制代码D:\soft\nginx\nginx-1.16.0>tasklist |findstr 15448
node.exe 15448 Console 2 30,252 K

六、日志

日志分类:

  • 第一:访问日志
    log``(server端最重要的日志)
    1
    2
    3
    4
    5
    6
    7
    * 第二:自定义日志(包括自定义事件、错误记录)


    #### 1. 操作文件时,node相关api


    * fs.readFile //读取文件

javascript复制代码fs.readFile(fileName, (err, data) => {
if (err) {
console.error(err)
return
}
// data 是二进制类型,需要转换为字符串
console.log(data.toString())
})

1
2

* fs.writeFile //写入文件

javascript复制代码const content = ‘这是新写入的内容\n’
const opt = {
flag: ‘a’ // 追加写入。覆盖用 ‘w’
}
fs.writeFile(fileName, content, opt, (err) => {
if (err) {
console.error(err)
}
})

1
2

* fs.exists // 判断文件是否存在

javascript复制代码fs.exists(fileName, (exist) => {
console.log(‘exist’, exist)
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

以上node操作文件的api,都是一次性读完、写完,如果文件过大,会很影响效率。


#### 2. IO操作的性能瓶颈


IO包括“网络IO”和“文件IO”。相比于CPU计算和内存读写,IO的突出特点就是:慢。


#### 3. stream


node已经完成了对stream功能的api实现:**req具有pipe()**,以流的形式,更合理的读文件、写文件。
以下是利用stream,合理的进行IO操作:

ini复制代码const http = require(‘http’)
const fs = require(‘fs’)
const path = require(‘path’)
const fileName1 = path.resolve(__dirname, ‘data.txt’)
const server = http.createServer((req, res) => {
if (req.method === ‘GET’) {
const readStream = fs.createReadStream(fileName1)
readStream.pipe(res)
}
})

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

#### 4. readline


readline 模块提供了一个接口,用于一次一行地读取可读流(例如 process.stdin)中的数据。


**总结:**



> * 日志对server的重要性
> * IO性能瓶颈,使用stream提高性能
> * 使用crontab拆分日志文件,使用readline分析日志内容


七、项目安全
------


* sql注入: 窃取数内容
* XSS攻击:窃取前端的cookie内容
* 密码加密:保障用户信息


#### 1. sql注入


sql是最原始、最简单的攻击,从有了web2.0就有了sql注入攻击。



> 攻击方式:输入一个sql片段,最终拼接成一段攻击代码
>
>
> 预防措施:使用mysql的escape函数处理输入内容即可。
> 执行sql注入攻击的效果:

ini复制代码const sql = select username, realname from users where username=${username} and password=${password}

1
2
3
4
5
6
7
8
9
10
11
12
13
14

![](https://gitee.com/songjianzaina/juejin_p9/raw/master/img/8521348a16ae80bc7fcd27e9fe5263040b836cfeac1dfce202f9c4637b5e98b1)
攻击者可以任意操作数据库。


#### 2. XSS攻击



> 攻击方式:在页面展示内容中参杂js代码,以获取网页信息
>
>
> 预防措施:转换生成JS的特殊字符
> 使用XSS处理输入的内容

css复制代码npm install xss –save

1
2

On Node.js

ini复制代码var xss = require(“xss”);
var html = xss(‘‘);
console.log(html);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#### 3. 密码加密


数据库被用户攻破,最不应该泄密的就是用户信息。



> 攻击方式:用户用户名和密码,在去尝试登陆其他系统
>
>
> 预防措施:将密码加密,即便拿到密码,也不知道明文密码


使用md5加密,如下:

javascript复制代码const crypto = require(‘crypto’)
// 密匙
const SECRET_KEY = ‘WJiol_8776#’
// 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)
}

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

#### 4. 项目总结



> * 处理http接口 //rquest,cookie,处理路由等
> * 连接数据库
> * 实现登录 //session,redis,
> * 安全
> * 日志 //stram,readline


**项目总流程图如下:**
![](https://gitee.com/songjianzaina/juejin_p9/raw/master/img/dc2395fcb7d624c1eada3a9ca11f8cc47c4928d7859ad517b8e2480b7f15d952)


八、express
---------


#### 1、安装


1. express脚手架安装
链接:[expressjs.com/en/starter/…](https://expressjs.com/en/starter/generator.html)
`npm install -g express-generator`
2. 实现登陆需要两个包


* express-session安装
链接:[github.com/expressjs/s…](https://github.com/expressjs/session)
`npm install express-session`
* connect-redis安装
链接:[github.com/tj/connect-…](https://github.com/tj/connect-redis)
`npm install connect-redis express-session`


#### 2、express的中间件概念

javascript复制代码//登陆校验的中间件
function loginCheck(req, res, next){
setTimeout(()=> {
res.json({
errno: -1,
msg: ‘登陆失败’
})
// next()
})
}

//路由匹配
router.get(‘/‘, loginCheck, function(req, res, next) {
res.send(‘respond with a resource’);
});

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

#### 3、总结


* 初始化代码中,各个插件的作用
* express如何处理路由
* express中间件


九、koa2
------


#### 1. 为什么使用koa2



> express 中间件是异步回调,koa2原生支持async/await
> 新开发的框架和系统,都是基于koa2,例如egg.js
> express虽为过时,但是koa2是未来趋势


#### 2. `async/await` 要点:



> 1.`await` 后面可以追加promise对象,获取`resolve`的值
> 2.`await`必须包裹在`async`函数里面
> 3`.async`函数执行返回的也是一个`promise`对象
> 4.`try-catch`获取`promise`中`reject`的值

javascript复制代码//简单的异步函数demo
async function readFileData(){
try{
const aData = await getFileContent(‘a1.json’)
const bData = await getFileContent(aData.next)
const cData = await getFileContent(bData.next)
}catch (err){
console.error(err)
}
}
readFileData();

1
2

#### 3. koa脚手架安装【koa1和koa2通用】

ruby复制代码$ npm install -g koa-generator

1
2

基于脚手架创建koa1项目:

shell复制代码$ koa2 /tmp/foo && cd /tmp/foo
$ npm install
$ npm start

1
2

基于脚手架创建koa2项目:

shell复制代码$ koa2 /tmp/foo && cd /tmp/foo
$ npm install
$ npm start

1
2

#### 4. 实现登陆需要两个包

css复制代码$ npm install koa-redis koa-generic-session redis –save

1
2
3
4
5

#### 5. 路由


(1)xss 安装: 预防xss攻击

css复制代码npm install xss –save

1
2

(2)MySQL安装

css复制代码npm install mysql –save

1
2
3

(3)morgan和koa-morgan: 打印日志
express支持morgan,不支持koa。koa需要安装中间件,`koa-morgan`

css复制代码npm install –save koa-morgan

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

#### 6. koa2中间件原理


十、上线与配置
-------


* 服务器稳定性
* 充分利用服务器硬件资源
* 线上日志记录


#### 1. PM2


简单介绍:


* 进程守护,系统崩溃自动重启
* 启动多进程,充分利用CPU和内存
* 自带日志记录功能


(1)下载

复制代码npm install pm2 -g

1
2

(2)常用命令

less复制代码pm2 start //启动
pm2 list //查看启动后的所有信息状态
pm2 restart [App name]/[id] // 重启
pm2 stop [App name]/[id] //停止
pm2 delete [App name]/[id] //删除
pm2 info [App name]/[id] //基础信息
pm2 log [App name]/[id] //查看log信息
pm2 monit [App name]/[id] //查看cpu、内存等信息

1
2
3
4
5
6
7
8
9

![](https://gitee.com/songjianzaina/juejin_p9/raw/master/img/f2a3317b13b22655b78b4e1f6416e182c2fe641582b170171932e3033e5214b8)
(3)进程守护


* `node app.js` 和`nodemon app.js`,进程崩溃则不能访问
* pm2遇到进程崩溃,会自动重启
(4)PM2配置
pm2的配置文件:

json复制代码{
“apps”: {
“name”: “pm2-test-server”,
“script”: “app.js”,
“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”
}
}


(5)多进程


使用多进程的理由:


* 为什么用多进程
* redis



> 使用多进程带来的问题:**多进程之间,内存无法共享**。
> 解决方案:多进程访问一个redis,实现数据共享


![](https://gitee.com/songjianzaina/juejin_p9/raw/master/img/b6b30d3c4da932bc65617c6ccb9d769e8ee108c71cd1c5e3cf567d76235c36b0)



**本文转载自:** [掘金](https://juejin.cn/post/6959583458779725860)

*[开发者博客 – 和开发相关的 这里全都有](https://dev.newban.cn/)*
0%