前言
express是基于Nodejs平台快速开放极简的web开发框架,它可以用来搭建web网站服务器或者api接口服务器,本文将详细列出利用express搭建一个web网站服务器的利用步调,其中包含一些搭建服务器过程中涉及到的Node.js相干的底子知识,接待各人一起来学习和讨论。
一、快速创建包管理配置文件
包管理配置文件里清楚的记录项目中安装了哪些包,此文件在开发情况中是必不可少的。准备一个文件夹存放项目文件,利用开发工具vscode打开项目文件夹,打开终端运行如下代码:
1、package.json
- //快速创建包管理配置文件 package.json
- npm init -y
复制代码 2、node_modules
node_modules文件夹中存放与项目有关的所有的包,此时运行以下命令,项目中还不会生成node_modules,而是生成了 package-lock.json,后续添加项目相干包就会主动生成node_modules了。
二、创建基本的web服务器
1、安装express
安装express命令如下:
安装完成后,项目根目录创建app.js文件,在 package.json中修改main入口文件为 app.js。如下图所示:
2、创建服务器
app.js添加代码,创建一个基本的web服务器。
- // 导入express
- const express = require('express')
- // 创建web服务器
- const app = express()
- // 启动web服务器
- app.listen(3380,()=>{
- console.log('server run at http://127.0.0.1:3380');
- })
复制代码 3、启动服务器
打开终端运行启动服务器,命令如下:
三、托管静态资源
1、调用express.static()
1.项目根目录下新建public文件夹,public文件夹下新建css(存放css相干样式文件)、images(存放图片相干)、js(存放js代码相干)文件夹 和index.html(用于启动服务器展示页)文件。
- //index.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>web服务器</title>
- </head>
- <body>
- <div>welcome to access web service...</div>
- </body>
- </html>
复制代码 2.app.js中调用express.static()托管静态资源
- // 托管静态资源
- app.use(express.static('./public'))
复制代码 3.项目有改动,重启服务器node ./app.js
,浏览器访问地址:http://127.0.0.1:3380/ ,页面可以看到index.html的内容,分析托管静态资源配置乐成。
2、托管多个静态资源
如果要托管多个静态资源目录,请多次调用express.static()函数,当访问静态资源文件时,express.static()函数会根据添加的顺序查找所需文件。
例如:
- //确保项目中有文件 public 和 upload
- app.use(express.static('./public'))
- app.use(express.static('./upload'))
复制代码 3、挂载路径前缀
如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以利用如下方式:
- app.use('/public',express.static('./public'))
复制代码 以上配置好之后就可以通过带有/public前缀的地址来访问public目录文件了,访问的地址示例:
http://127.0.0.1:3380/public/index.html
四、nodemon工具
1、为什么利用nodemon
nodemon可以监听项目文件的变动,当代码被修改,nodemon会主动资助我们重启项目,进步了开发效率。
2、安装nodemon
在终端中,运行如下命令,即可将nodemon安装为全局可用的工具:
3、利用nodemon
在没有安装nodemon之前,启动项目利用node ./app.js
如今安装了nodemon,将启动命令更换为:
五、 express路由
在express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。express中的路由分3个部门组成,分别是请求的类型、请求的URL地址、处理函数。利用路由最基本的方式就是挂载到app身上。格式如下:
模块化路由
express不建议将路由直接挂载到app上,推荐将路由抽离为单独的模块。将路由抽离为单独模块的步调如下:
1.创建对应的.js路由模块文件
2.调用express.Router()创建路由对象
3.向路由对象上挂载详细的路由
4.利用module.exports向外共享路由对象
5.入口文件中利用app.use()注册路由模块
1、 创建用户路由模块
下面抽离用户路由模块的示例:
根目录下新建用户路由模块/router/user.js 示例代码如下:
- // 导入express
- const express = require('express')
- // 创建路由对象
- const router = express.Router()
-
- // 导入路由处理函数
- const userRouterHandler = require('../router_handler/user')
- // 获取用户列表的路由
- router.get('/userlist',userRouterHandler.getUserListHandle)
- // 更新用户信息的路由
- router.put('/userinfo',userRouterHandler.updateUserInfoHandle)
- // 向外导出路由对象
- module.exports = router
复制代码 根目录下新建用户路由处理函数 /router_handler/user.js 示例代码如下:
- // 获取用户信息路由处理函数
- exports.getUserListHandle = (req,res)=>{
- // 相关逻辑...
- res.send('ok')
- }
- // 更新用户信息路由处理函数
- exports.updateUserInfoHandle = (req,res)=>{
- // 相关逻辑...
- res.send('ok')
- }
复制代码 在入口文件app.js导入并注册用户路由模块,示例代码如下:
- // 导入并注册用户路由模块
- const userRouter = require('./router/user')
- //根据需求配置路由前缀 /api
- app.use('/api',userRouter)
复制代码 2、启动测试
nodemon ./app.js
启动项目
利用api接口测试工具(这里利用Postman) 测试接口 :
http://127.0.0.1:3380/api/userlist
http://127.0.0.1:3380/api/userinfo
下图展示Postman测试接口:
3、项目目录截图
六、全局见效的中间件
客户端发起的任何请求,到达服务器之后,都会触发中间件,叫做全局见效中间件。
通过app.use(中间件函数),即可定义一个全局见效的中间件,中间件本质上是一个function处理函数。
1、express内置的中间件
express.json() 解析JSON格式的请求体数据
express.urlencoded() 解析URL-encoded格式的请求体数据
app.js入口文件,所有路由之前注册这两个中间件:
- // 处理post数据
- app.use(express.json())
- //处理xxx-www-urlencoded数据
- app.use(express.urlencoded({ extended:false }))
复制代码 2、解析token中间件(JWT相干)
1.JWT认证机制相干
什么是JWT:目前最流行的跨域认证解决方案。
JWT原理:用户的信息通过Token字符串的形式,保存在客户端浏览器中,服务器通过还原Token字符串的形式来认证用户的身份。
JWT组成三部门:Header(头部)、Payload(有效荷载)、Signature(署名)
JWT推荐利用方式:把JWT放在HTTP请求头的Authorization字段中,格式:Authorization:Bearer <token>
2.安装
jsonwebtoken 用于生成JWT字符串
express-jwt 用于将JWT字符串解析还原成JSON对象
- //安装npm install
- jsonwebtoken@8.5.1 express-jwt@5.3.3
复制代码 3.配置中间件
根目录下新建config.js文件,代码如下:
- module.exports = {
- jwtSecretKey:'pet_web_poppop No1.**', //密钥
- expiresIn:'10h' //token有效期
- }
复制代码 app.js文件中,路由之前配置中间件,代码如下:
- // 导入 config.js 配置文件
- const config = require('./config')
- // 导入解析token中间件
- const expressJWT = require('express-jwt')
- //expressJWT({secret:config.jwtSecretKey}) 用来解析token的中间件
- //unless({path:[/^\/api\//]}) 用来指定哪些接口不需要访问权限
- app.use(expressJWT({secret:config.jwtSecretKey}).unless({path:[/^\/api\//]} ))
复制代码 4.利用JWT (在登录乐成后生成JWT字符串)
调用 jsonwebtoken 包提供的 sign() 方法,将用户信息加密成JWT字符串,相应给客户端。
留意:千万不要把密码加密到token字符串中
代码如下:
- // router/user.js
- // 导入路由处理函数
- const userRouterHandler = require('../router_handler/user')
- // 登录
- router.post('/login',userRouterHandler.userLoginHandle)
- // /router_handler/user.js
- // 导入jwt 相关包
- const jwt = require('jsonwebtoken')
- // 登录处理函数
- exports.userLoginHandle = (req,res)=>{
- let userinfo = req.body
- // 登录失败情况下的代码省略....
- // 用户登录成功后,生成JWT 字符串,通不过token属性响应给客户端
- res.send({
- status:200,
- message:'登录成功!',
- token:jwt.sign({username:userinfo.username},config.jwtSecretKey,{
- expiresIn:config.expiresIn
- })
- })
- }
复制代码 3、优化res.send()
res.send()方法用于发送相应数据给客户端,我们在app.js入口文件封装优化它,
必要留意:除了错误级别的中间件在所有路由之后配置 其他的中间件都要在路由之前配置。
- // 应用级别的中间件(全局中间件)
- app.use((req,res,next)=>{
- res.an = (err,status=1)=>{
- res.send({
- status,
- // 判断err是错误对象还是字符串
- message: err instanceof Error ? err.message : err
- })
- }
- next()
- })
复制代码 4、封装错误级别的中间件
错误级别的中间件作用:专门用来捕捉整个项目标异常错误,从而防止项目异常瓦解题目。我们在app.js入口文件封装它,留意:错误级别的中间件必须注册在所有路由之后!
- //全局错误级别的中间件 捕获验证失败的错误
- app.use((err,req,res,next)=>{
- //...
- if(err.name === 'UnauthorizedError') return res.an('身份认证失败!',401)
- // 未知错误
- res.an(err)
- })
复制代码 七、 配置cors跨域
1、安装
2、配置
app.js入口文件中注册 cors中间件为全局中间件
- //导入中间件
- const cors = require('cors')
- //将cors 注册为全局中间件
- app.use(cors())
复制代码 八、优化表单数据验证
在实际开发中,前后端都必要对表单的数据进行合法性的验证,而且后端作为数据合法性验证的末了一个关口,在拦截非法数据方面,起到了至关重要的作用。利用第三方数据校验模块,来降低出错率,进步验证的效率与可维护性。
1、安装
- //joi 定义验证规则npm install
- joi// @escook/express-joi 实现主动对表单数据进行验证npm i @escook/express-joi
复制代码 2、利用
新建 / validate/user.js 用户信息验证规则模块 并初始化代码如下:
- //导入joi 验证规则
- const joi = require('joi')
- /**
- * string() 值必须是字符串
- * aiphanum() 值只能是包含a-zA-Z0-9的字符串
- * min(length) 最小长度
- * max(length)最大长度
- * required() 值是必填项 不能为undefined
- * pattern(正则表达式) 值必须符合正则表达式的规则
- * **/
- // 用户名验证规则
- const username = joi.string().alphanum().min(1).max(10).required()
- //密码验证规则
- const password = joi.string().pattern(/^[\S]{6,12}$/).required()
- // 注册和登录表单的验证规则对象
- exports.reg_login_validate = {
- // 表示需要对 req.body 中的数据进行验证
- body:{
- username,
- password
- }
- }
复制代码 在/router/user.js 路由模块中进行验证,代码如下:
- const expressJoi = require('@escook/express-joi')
- const {reg_login_validate} = require('../validate/user')
- // 登录
- router.post('/login',expressJoi(reg_login_validate),userRouterHandler.userLoginHandle)
复制代码 入口文件app.js中在全局错误级别的中间件配置捕捉验证失败的错误,代码如下:
- // 导入验证规则
- const joi = require('joi')
- app.use((err,req,res,next)=>{
- // 验证表单数据,捕获失败错误
- if(err instanceof joi.ValidationError) return res.an(err)
- if(err.name === 'UnauthorizedError') return res.an('身份认证失败!',401)
- // 未知错误
- res.an(err)
- })
复制代码 九、 安装并配置mysql模块
1、安装
2、配置
在项目根目录下新建 /db/index.js ,并初始化代码如下:
- // 导入mysql模块
- const mysql = require('mysql')
- // 创建数据库连接对象
- const db = mysql.createPool({
- host:'127.0.0.1', //数据库地址
- user:'root', //数据库用户名
- password:'123456', //数据库密码
- database:'my_database' //数据库名称
- })
- // 向外共享 db 数据库连接对象
- module.exports = db
复制代码 3、利用示例
在用户路由处理函数模块中 router_handler/user.js 导入数据库毗连对象,获取数据库用户信息
- // 导入数据库连接对象
- const db = require('../db/index')
- exports.getUserListHandle = (req,res)=>{
- // 定义查询用户的 sql 语句 首先确保你的数据库创建了user表
- const sql = 'select * from user where is_delete=0'
- db.query(sql,(err,results)=>{
- // 错误处理
- if(err) return res.an(err)
- // 查询成功处理
- res.send({
- status:200,
- message:'获取用户信息成功!',
- data:results
- })
- })
- }
复制代码 十、对密码进行加密处理bcryptjs
为了保证密码的安全性,不建议在数据库以明文的形式保存用户密码,下面介绍利用bcryptjs对密码进行加密处理。
1、安装
2、利用
在用户注册时对密码进行加密,再将信息保存到数据库中。
或者用户登录时检测输入的密码与数据库的密码是否同等。示例代码如下:
- // router_hadler/user.js
- //导入加密包 对密码加密
- const bcrypt = require('bcryptjs')
- //用户注册处理函数
- exports.userRegisterHandle = (req,res)=>{
- const userinfo = req.body
- // 此处省略注册逻辑代码...
- //使用bcryptjs对密码进行加密处理
- console.log('加密之前密码:',userinfo.password);
- userinfo.password = bcrypt.hashSync(userinfo.password,10)
- console.log('加密之后密码:',userinfo.password);
- //...
- })
- }
- //用户登录判断输入密码是否与数据中的密码一致
- exports.userLoginHandle = (req,res)=>{
- //登录逻辑省略...
- const compareResults = bcrypt.compareSync(输入的密码数据,数据库密码数据)
- if(!compareResults) return res.cc('登录失败!')
- //...
- })
- }
复制代码 十一、利用svg-captcha和 cookie-parser生成图形验证码并保存到cookie中
svg-captcha 用于生成svg格式的验证码图片
cookie-parser 是express的一个中间件,用来实现对cookie的解析
1、 安装
- npm install
- cookie-parsernpm install
- svg-captcha
复制代码 2、注册 cookie-parser为全局中间件
app.js中代码:
- // 导入包
- const cookieParase = require('cookie-parser')
- //注册
- app.use(cookieParase())
复制代码- // router/user.js
- // 导入路由处理函数
- const userRouterHandler = require('../router_handler/user')
- //获取图形验证码
- router.get('/getcode',userRouterHandler.getCode)
- // /router_handler/user.js
- //获取生成的图形验证码处理函数
- exports.getCode = (req,res)=>{
- let captcha = svgCaptcha.create({
- // 翻转颜色
- inverse:false,
- // 字体大小
- fontSize:36,
- // 噪声线条数
- noise:2,
- // 宽度
- width:80,
- // 高度
- height:30,
- })
- // 保存到session 忽略大小
- req.session = captcha.text.toLowerCase()
- console.log(req.session);
- // 保存到cookie 方便前端调用验证
- res.cookie('captcha',req.session)
- res.setHeader('ContentType','image/svg+xml')
- res.write(String(captcha.data))
- res.end()
- }
复制代码 十二、multer解析表单数据(用于文件上传)
单文件上传 以及 多文件上传
用户路由模块中处理上传用户头像操作,代码如下:
- // router/user.js
- // 导入multer
- const multer = require('multer')
- // 设置存储引擎
- const storage = multer.diskStorage({
- //文件存储路径
- destination: function (req, file, cb) {
- //保证项目中有此文件
- cb(null, './public/upload');
- },
- //存储的文件名处理
- filename: function (req, file, cb) {
- cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
- }
- });
- const upload = multer({ storage:storage})
- // 导入路由处理函数
- const userRouterHandler = require('../router_handler/user')
- //,upload.single() 单文件上传
- //上传用户头像 user_pic 保存用户头像的字段
- router.put('/updateuser',upload.single('user_pic').userRouterHandler.updateUserInfo)
- //上传相册 upload.array(数据库相册的字段,限制上传大小)
- router.put('/userpicture',upload.array('user_pics',12).userRouterHandler.updateUserPicture)
- //router_handler/user.js 用户路由处理函数模块
- //上传用户头像处理函数
- exports.updateUserInfo = (req,res)=>{
- //req.file 上传的图片信息
- console.log(req.file)
- //处理图片操作...
- }
- //上传相册 处理函数
- exports.updateUserPicture = (req,res)=>{
- //使用req.files接收 上传的图片信息
- console.log(req.files)
- //处理图片操作...
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |