0%

基于nodejs的express搭建后端服务器


什么是express

express是node.js的一个库,可以让我们搭建一个后端的服务器
通俗的讲:express负责后端,vue负责前端,它俩之间使用HTTP来进行数据交换

搭建项目(前后端分离 vue + express )

新建项目文件夹express_vue

后端 - express环境搭建

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
39
40
41
42
43
44
45
46
47
48
// cd 进入文件夹express_vue
cd express_vue

//全局安装express
npm install express -g

//全局安装Express 脚手架工
npm install express-generator -g

// express --version 来检测是否安装成功


// 创建 express项目, 利用express-generator 脚手架快速生成项目
express --no-view server
// 该命令即创建了一个名为 server的无视图 express 项目,项目目录如下:
├─bin
├─www // 启动项目,默认监听3000端口
├─public // 存放静态文件(images, js, css)
├─images文件夹
├─javascripts文件夹
├─stylesheets文件夹
├─style.css
├─index.html
├─routes // 存放路由文件,路由就是用来确定URL和资源的对应关系的,这里面的代码主要用来接收前端的请求,然后进行响应 ,我们需要在里面写后台的那些接口
├─index.js
├─users.js
├─app.js // 整个项目的入口文件,在这里面引入一些项目需要的模块,创建 express 实例,进行总体路由设置等
├─package-lock.json // 执行完 npm install 后生成的,里面是已经安装的依赖包的详细描述,需要上传到 git 上,以保证其他人在 install 的时候,大家的依赖版本相同
└─package.json // 依赖包描述文件,这里面有的依赖包可以通过 npm install 一键安装
views 目录存放模板引擎文件,这里面的文件最终会渲染为html页面

//进入项目目录下(/server),执行 npm install 来安装项目所需的依赖模块
cd server

npm install

//执行命令 npm start 启动项目,通过浏览器访问 http://localhost:3000/
npm start

http://localhost:3000/ (显示welcome to Express即启动成功)


//法二
//创建项目也可以使用下面的创建,不用express --no-view server
express 想要创建的项目名 //express 项目名称
cd 创建的项目名 //进入项目
npm install
npm run start

###nodejs插件

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
1、nodemon 代码热更新
//调试Nodejs项目时,修改代码,要手动close掉,再重新启动,非常繁琐
//可使用[nodemon](https/www.npmis.com/package/nodemon)这个工具,它能够监听项目文件的变动,当代码被修改后,nodemon会自动帮我们重启项目,极大方便了开发和调试

npm install -g nodemon //全局安装

// 项目根目录下创建nodemon.json文件
{
"restartable": "rs", //设置重启模式
"ignore": [ //设置热更新忽略的文件
".git",
".svn",
"node_modules/**/node_modules"
],
"verbose": true, //设置日志输出模式,true 详细模式
"execMap": { //设置运行服务的后缀名与对应的命令
"js": "node --harmony"
},
"watch": [], //监听哪些文件的变化,当变化的时候自动重启
"env": {
"NODE_ENV": "development"
},
"ext": "ejs js json" //监控指定的后缀文件名
}

//更改启动命令
更改package.json中的scripts下的start、把node换成nodemon
{
"scripts": {
"start": "nodemon ./bin/www"
}
}
//上述步骤全部成功之后重启服务验证,关闭当前服务后我们从新npm start启动服务

2、body-parser
//express中没有内置的获取post请求体的api,需要第三方包 body-parser,body-parser是解析req.body,不然body不会被解析

cnpm i body-parser -save
//app.js配置
var jsonParser = bodyParser.json();
var urlencodedParser = bodyParser.urlencoded({extended: false});

3、加密包 bcryptjs
npm i bcryptjs@2.4.3

4、表单验证的包
npm install @escook/express-joi
npm install @hapi/joi@17.1.0
npm i joi //Cannot mix different versions of joi schemas
const joi = require('joi') //用joi代替@hapi/joi@17.1.0

5、项目集成babel,支持ES6等新语法
//写着写着,你发现连基础的Import都无法使用,await async也不能用。比如,我const一个常用,它就报错了
//因为你用的语法太新了,是ES6以后的新语法,我们需要用babel转换一下

//安装babel相关的库支持。cmd执行以下命令:
npm install babel babel-node babel-cli --save-dev
npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
npm install babel-preset-env --save-dev
//以上命令请自行百度用途,先照着做,npm会自安装相关的包。其中 --save -dev表示仅保存到当前项目和调试环境。
安装完以后,会自动更新package.json文件,在devDependencies中增加了相关的babel库支持

//修改start脚本。
在package.json,将scripts的start命令,增加 --exec babel-node命令,完整如下:
"start": "nodemon --watch src --watch config src/index.js --exec babel-node"

//重新运行项目 就可以去玩代码了 ,写你需要的代码,扩充你的项目

前端 - vue环境搭建

1
2
3
4
5
6
7
8
9
// cd 进入文件夹express_vue
cd express_vue

// 正常用脚手架创建vue项目
//安装axios等插件
npm install axios --save

// 启动项目
npm run dev / npm run serve

前后端交互(跨域问题)

注意:使用这两种方法时需要在Express使用路由前修改

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//解决跨域方式一 -- 官方推荐的中间件cros
// 使用cros中间件实现跨域

//安装中间件
npm install cors //运行npm install cors安装中间件
const cors = require('cors') //使用const cors=require(’cors‘)导入中间件
app.use(cors()) //在路由之前调用app.use(cors())配置中间件


import express, { Express, Router } from 'express';
const app: Express = express();
const router: Router = express.Router();

var cors = require("cors");
app.use(cors());
//注意:使用这两种方法时需要在Express使用路由前修改
app.get('/list', ()=>{
});

//注意事项:
①CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了CORS的接口。
②CORS在浏览器中有兼容。只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了CORS的服务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。

//设置响应头,处理跨域请求(setHeader)
app.all('/cors-server', function(req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
// 允许客户端额外想服务器发送 Content-Type 请求头和 X-Custom-Header 请求头
res.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-type,X-Requested-With,Authorization")
res.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
res.send('CORS 跨域请求')
})

//解决跨域方式二 -- 手动添加头信息
//实现跨域访问,要想前后端可以交互,要配置跨域访问
express文件夹中的app.js文件中粘贴如下代码

import express, { Express, Router} from 'express';
const app: Express = express();

app.all('*', function(req, res, next) {
// 设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin", "*"); //包含本域地址
// 允许的header类型
res.header("Access-Control-Allow-Headers", "X-PINGOTHER,Content-type,X-Requested-With,Authorization");
// 跨域允许的请求方式
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
// 让options 尝试请求快速结束
res.header("Content-Type", "application/json;charset=utf-8");
next();
})
//注意:使用这两种方法时需要在Express使用路由前修改
app.use("/api", router);

app.get("/list", ()=>{
// 请求内容
});








//连接mysql数据库
cd到后端文件夹根目录,安装数据库模块
npm i mysql

//连接数据库
新建一个utils文件夹,创建pool.js(名字随便取),用于配置数据库连接,粘贴下面代码
// 连接mysql数据库
// 数据库连接池
require('babel-polyfill'); // 兼容性问题
var mysql = require('mysql');
//建立连接池
var pool = mysql.createPool({
host: 'localhost',
user: '*****', //用户名
password: '*****', //密码
database: '*****', //要连接数据库名
//设置超时时间解决握手不活动超时问题
connectionLimit: 1000,
connectTimeout: 60 * 60 * 1000,
acquireTimeout: 60 * 60 * 1000,
timeout: 60 * 60 * 1000,
});
// 取出连接
function getPoolConnection() {
let p = new Promise((resolve, reject) => {
// 从连接池中取出连接 err:错误信息 conn:从连接池中取出的连接对象,通过这个对象去访问数据库
pool.getConnection((err, conn) => {
// 成功信息
if (err) {
// 失败信息
reject("mysql数据库连接失败!失败原因:" + err);
} else {
resolve(conn);
}
});
})
return p;
}
//执行sql
function execute(sql) {
return new Promise(function(resolve, reject) {
var connection;
//then中有2个参数,第⼀个参数是状态变为成功后应该执⾏的回调函数,第⼆个参数是状态变为失败后应该执⾏的回调函数
getPoolConnection().then(function(conn) {
conn.query(sql, function(err, result) {
if (err) {
console.log("sql错误");
console.log(err);
reject(err);
} else {
resolve(result);
console.log("sql执行完成");
// console.log(result)
conn.release();
// console.log("释放完成");
}
});
}).catch(function(err) {
reject(err)
})
});
}
module.exports = {
getPoolConnection,
execute
};

项目打包 – Vue项目安装打包上传到Express服务器

项目写好了,如何发布到服务器部署呢?

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
1、vue项目执行打包,生成dist文件夹
npm run build

进入到dist/index.html,使用浏览器运行,页面如果空白报错,解决方法
修改,项目根目录下config/index.js,修改一处
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './', // 未修改前是 / 修改之后 ./
/**
* Source Maps
*/
vue项目打包后css背景图路径不对的问题,解决办法为:在build/utils.js文件中添加一行代 publicPath:'../../'
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader',
publicPath: '../../'
})
} else {
return ['vue-style-loader'].concat(loaders)
}

2、将vue打包的文件放到Nodejs下运行
①将vue打包生成dist文件下所有的文件复制到express项目的public中
②express项目中,打开app.js文件,将“app.use('/', indexRouter);”注释掉。(如果要展示vue项目,忽略此步)
③改完后,重新启动express项目 npm start
④运行express,在浏览器中输入localhost:3000
⑤如果express运行错误,回到vue项目gw_demo/build/ vue-loader.conf.js将isProduction 改成false
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: false //isProduction 改成false
})

//运维如何管理?
//你需要把package.json+dist文件夹一起打包给运维。运维执行直接执行:npm i ,就可以安装所有的包。
//然后执行npm run serve命令运行相关后端服务。
//当然,一般运维会用pm2来部署,即pm2 start dist/index.js --name server

3、关闭终端 ,云服务就断了,网页无法访问
可以使用pm2
//安装pm2
npm i pm2 -g

//启动项目
pm2 start ./bin/www

//项目运行的时候一刷新页面就会报404
使用connect-history-api-fallback中间件解决
npm install --save connect-history-api-fallback

修改express创建项目下app.js文件

var app = express(); //express框架模块
var history = require('connect-history-api-fallback'); //这个是重点

app.use(history()); //使用history 最好放到pubic静态目录前
app.use(express.static(path.join(__dirname, 'public')));


express中间件

Express的中间件,本质上是function处理函数

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
39
40
41
42
43
44
45
46
47
48
49
50
51
const zjj = function(req,res,next){
next() //当前业务处理完后,必须调用next函数,把关系转交给下一个中间件或路由
})
注:
①中间件函数的形参列表中,必须包含next参数,而路由处理函数只包含req和res

②next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。

//全局生效的中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件
const mw = function(req,res,next){
console.log('交给下一个,lm,popst')
next()
}
app.use(mw)
app.use(function(req,res,next){ //全局中间件的简化形式
next()
})

//中间件作用
多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req 或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用

//定义多个全局中间件
使用app.use()连续定义多个全局中间件,按定义的顺序执行

//局部生效的中间件
不使用app.use()定义的中间件,叫做局部生效的中间件
const mw1 = function(req,res,next){
console.log('局部中间件')
next()
}
app.get('/user',mw1,function (req,res) {
res.send('请求')
})

//定义多个局部中间件
app.get('/user',mw1,mw2,function (req,res) {
res.send('请求')
})

//注意事项
①一定要在路由之前注册中间件

②客户端发送过来的请求,可以连续调用多个中间件进行处理

④执行完中间件的业务代码之后,不要忘记调用next()函数

④为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码

⑤连续调用多个中间件时,多个中间件之间,共享req和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
38
39
40
41
42
43
44
1)应用级别的中间件

通过app.use()或app.get()或app.post(),绑定到app实例上的中间件,叫做应用级别的中间件

2)路由级别的中间件

绑定到express.Router0实例上的中间件,叫做路由级别的中间件。router.use()

3)错误级别的中间件

错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。

参数格式有:(err,req,res,next)

app.get('/url',(req,res)=>{
throw new Error('服务器发生错误了wl')
res.send('新请求')
})
app.use(function(err,req,res,next){
console.log('中间件')
console.log('错误' + err.message)
next()
})

注意:错误级别的中间件,必须注册在所有路由之后!


4)Express内置的中间件

①express.static 快速托管静态资源的内置中间件,例如:HTML文件、图片、CSS样式等(无兼容性)

②express.json 解析JSON格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)③expres.urlencoded 解析URL-encoded 格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)

//默认情况下,如果不配置解折表单数据的中间件,则req.body默认等于undefined
app.use(express.json())
app.use(express.urlencoded({extended:false}))

5)第三方的中间件

按需下载并配置中间件,提高开发效率
npm install body-parser
const bodyPaser = require('body-parser')
app.use(bodyPaser)

自定义中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
自己手动模拟一个类似于express.urlencoded这样的中间件,来解析POST提交到服务器的表单数据。

步骤:

①定义中间件

②监听req的data事件

③监听req的end事件

④使用querystring 模块解析请求体数据

⑤将解析出来的数据对象挂载为req,body

⑥将自定义中间件封装为模块

app.use(function(req,res,next){

})

1

1

1

1

1

1

1

1

------ The End ------
您的认可是我不断进步的动力!