expres搭建一个基本的web网站服务器详细步骤

前言

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了。

npm install

二、创建基本的web服务器

1、安装express

安装express命令如下:

npm install 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、启动服务器

打开终端运行启动服务器,命令如下:

node ./app.js

三、托管静态资源

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安装为全局可用的工具:

npm install -g nodemon

3、使用nodemon

在没有安装nodemon之前,启动项目使用node ./app.js
现在安装了nodemon,将启动命令替换为:

nodemon ./app.js

五、 express路由

在express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。express中的路由分3个部分组成,分别是请求的类型、请求的URL地址、处理函数。使用路由最基本的方式就是挂载到app身上。格式如下:

app.METHOD(PATH,HANDLER)

模块化路由

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、安装

npm i cors@2.8.5

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、安装

npm i mysql@2.18.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、安装

npm i bcryptjs@2.4.3

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-parser
npm 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)
	//处理图片操作...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值