引入 express,启动服务
const express = require('express')
const app = new express()
const router = express.Router()
app.use(router)
// 启动服务,服务开在本地80端口
app.listen(80, () => {
console.log('server running at http://127.0.0.1')
})
express 解析 post 请求体+解析 json 数据
app.use(express.urlencoded({ extended: false }))
app.use(express.json())
后端允许跨域
const cors = require('cors') //中间件解决跨域
app.use(cors())
express 静态资源托管
app.use('/upload', express.static('upload'))
// 将upload目录配置为可被外界访问的资源
// 访问地址 http://xxx.xxx.xxx.xxx/upload/xxx.jpg
nodejs path 模块
__dirname 获取当前文件所在的绝对路径,不包括文件名
__filename 获取当前文件所在的绝对路径,包括文件名
获取路径:path.dirname()
获取文件名(带有扩展名):path.basename()
获取文件名(没有扩展名):path.basename( , ".后缀")
获取文件的扩展名:path.extname()
路径连接:path.join()
转化成绝对路径:path.resolve()
解析路径 :
path.parse(){
root : 根路径
dir : 路径名
base : 文件名.后缀名
ext : 后缀名
name : 文件名,不包括后缀名
}
nodejs fs 模块
操作文件夹
创建文件夹
异步创建文件夹 mkdir(path, options,callback) path:用来设置文件夹的路径 options:用来设置文件夹的操作权限{mode: 077} callback:回调函数,当文件夹创建完毕时执行,该函数有两个参数(err,path)–err 代表错误信息,在文件夹创建失败时返回 err
// 异步创建文件夹
fs.mkdir(path.join(__dirname, 'files'), { mode: 077 }, function (err, dirPath) {
if (err) {
console.log('文件夹创建失败')
}
console.log(dirPath)
})
同步创建文件夹,即文件夹创建时后面的代码处于阻塞状态,直达文件夹创建完毕 mkdirSync(path, options) path:用来设置文件夹的路径 options:用来设置文件夹的操作权限{mode: 077} callback:回调函数,当文件夹创建完毕时执行,该函数有两个参数(err,path)–err 代表错误信息,在文件夹创建失败时返回 err
// 同步创建文件夹
fs.mkdirSync(path.join(__dirname, 'files'), { mode: 077 })
删除文件夹
异步文件夹 rmdir(path, callback) path:用来设置文件夹的路径 callback:回调函数,当文件夹删除完毕时执行,该函数有一个参数(err)–err 代表错误信息,在文件夹删除失败时返回 err
// 异步删除文件夹
fs.rmdir(path.join(__dirname, 'files'), function (err) {
if (err) {
console.log('文件夹删除失败')
console.log(err)
}
console.log('文件夹删除成功')
})
同步删除文件夹 fs.rmSync(path) path:用来设置文件夹的路径 注意:删除文件夹时,文件夹必须为空。如果文件夹不为空,此时文件夹无法正常删除
// 同步删除文件夹
fs.rmSync(path, join(__dirname, 'files'))
查询文件夹
异步查询文件夹中的子级文件 readdir(path, callback) path:读取的文件夹路径 callback:读取之后对应的回调,err 代表读取失败信息,files 数组,存储读取成功的文件夹子级文件名称
// 异步查询文件夹
fs.readdir(path.join(__dirname, 'files'), function (err, files) {
if (err) {
console.log('文件夹读取失败')
}
console.log(files)
})
同步查询文件夹中的子级文件 readdirSync(path) path:读取的文件夹路径
var fs = fs.readdirSync(path.join(__dirname, 'files'))
console.log(fs)
非空文件夹删除
读取非空文件夹中所有的文件或者文件夹 将文件直接删除,但是文件夹需要继续读取,将子级文件夹清空以后再删除 2.1. 首先判定获取的内容是否是文件或者文件夹
//异步获取
fs.stat(path.join(__dirname,"files"),function (err,states) {
if(err){
console.log("读取失败");
}
console.log((states.isDirectory()));
})
//同步获取
var state = fs.statSync(path.join(__dirname, "files"));
console.log(state.isDirectory());
//用来返回一个文件状态,该状态对象中分别存在个方法。isDirectory()返回该文
件是否是文件夹,isFile()返回该文件是否是文件类型
如果数据是文件直接删除,如果不是继续读取该文件中的子级文件或文件夹
//读取当前path对应的文件中的所有子级文件或者文件夹
var files = fs.readdirSync(pathName)
// 判断:当前读取的子级文件是否是文件类型
for (var index in files) {
var filePath = path.join(pathName, files[index])
console.log(filePath)
//判断filePath对应是文件还是文件夹
var state = fs.statSync(filePath)
if (state.isFile()) {
//文件此时要同步删除
fs.unlinkSync(filePath)
} else {
//继续执行删除文件夹操作
deleteDir(filePath)
}
}
最后将当前文件夹删除
// //删除当前空文件夹
fs.rmdirSync(pathName)
完整代码
//定义一个函数完成文件夹的删除
function deleteDir(pathName) {
//读取当前path对应的文件中的所有子级文件或者文件夹
var files = fs.readdirSync(pathName)
// 判断:当前读取的子级文件是否是文件类型
for (var index in files) {
var filePath = path.join(pathName, files[index])
console.log(filePath)
//判断filePath对应是文件还是文件夹
var state = fs.statSync(filePath)
if (state.isFile()) {
//文件此时要同步删除
fs.unlinkSync(filePath)
} else {
//继续执行删除文件夹操作
deleteDir(filePath)
}
}
// 删除当前空文件夹
fs.rmdirSync(pathName)
}
deleteDir(path.join(__dirname, 'files'))
文件操作
从文件中读取数据
异步读取文件数据
fs.readFile(path, options, callback)–从文件中异步读取文件数据。注意 callback 存在两个参数 err,data。err 当读取失败时抛出错误信息。data 用来存储读取成功之后对应的文件数据。
fs.readFile(
path.join(__dirname, 'a.txt'),
{ encoding: 'utf-8', flag: 'r+' },
function (err, data) {
if (err) {
console.log('数据读取失败')
}
console.log(data)
},
)
同步读取文件数据 fs.readFileSync(path, options)–从文件中同步读取文件数据
//同步读取文件数据
var data = fs.readFileSync(path.join(__dirname, 'b.txt'), {
encoding: 'utf-8',
flag: 'r',
})
console.log(data)
注意:对文件进行数据读取时,一定要保证读取的文件提前是存在的,如果被读取的文件不存在,计算机不会自动创建,会自动抛出异常。
向文件中写入数据
异步写入数据 fs.writeFile(path, data, options, callback)–向文件中异步写入数据
fs.writeFile(
path.join(__dirname, 'a.txt'),
'八百里分麾下炙',
{ encoding: 'utf-8', flag: 'a' },
function () {
console.log('数据已经写入')
},
)
同步写入数据 fs.writeFileSync(path, data, options)–向文件中同步写入数据。
fs.writeFileSync(path.join(__dirname, 'a.txt'), '你好', {
encoding: 'utf-8',
flag: 'w',
})
注意:向文件中写入数据,如果不存在,此时会自动创建
删除文件
异步删除:
//文件是否存在,都会回调函数,文件删除成功
fs.unlink(path.join(__dirname), 'a.text', function () {
console.log('文件删除成功')
})
同步删除:
fs.unlinkSync(path.join(__dirname, 'a.text'))
获取文件信息
异步获取文件信息
// 获取文件信息
fs.stat(path.join(__dirname, 'a.txt'), function (err, states) {
if (err) {
console.log('文件不存在')
}
console.log(states)
})
fs.stat(path.join(__dirname, "b.txt"), function(err, stats){
if(err){
console.log('文件不存在');
}
//stats是一个文件状态对象,可以通过该对象内置的isFile()或者isDirectory()
判断当前文件是文件夹类型还是文件类型,对应的返回值是一个布尔类型。
console.log(stats.isDirectory());
});
同步获取
var stats = fs.statSync(path.join(__dirname, 'b.txt'))
console.log(stats.isFile()) //布尔类型
重命名文件
异步:
// 文件重命名
fs.rename(path.join(__dirname, "b.txt"), path.join(__dirname,
"block.txt"), function(){
console.log('文件重命名成功');
同步:
fs.renameSync(path.join(__dirname, 'b.txt'), path.join(__dirname, 'block.txt')) //如果不存在会抛出异常
综上:文件的操作分为同步和异步操作,异步操作均对异常做出了处理,但是同步操作没有对异常做出处理,因此使用时最好选用异步操作。
常用的第三方模块
# i是install的缩写,删除时可以使用un代替i,un既是uninstall的缩写
npm i express-generator -g # 安装全局express脚手架
express xxx -e # 创建基于.ejs的项目
npm i -g nodemon # 这个安装为全局,用来解决实时刷新页面,实现node服务器与数据库服务器的重启
npm i multer # 安装编写上传文件接口需要的模块
npm i bcryptjs # 安装密码加密需要的模块
npm i jsonwebtoken # 安装服务器端传送token需要的模块
npm i express-jwt # 安装验证token存不存在需要的模块
npm i cors # 安装服务器端解决跨域需要的模块
npm i moment # 安装日期格式化需要的模块
npm i mongoose # 安装使用mongoDB数据库需要的模块
npm i body-parser # 安装解决上传文件大小受限需要的模块
npm i cheerio # 实现服务器端操作DOM
# 非常常用,内部封装了ajax,通常也是用来发送四种方式的请求,
# get,post,put,delete(这种方式没有数据,只有一个参数url,传参时要在url后面进行拼接)
npm i axios
jwt token 校验
// token认证
// 安装导入JWT相关的包
const jwt = require('jsonwebtoken')
const expressJwt = require('express-jwt')
const secret = 'guoyanchao No1 ^_^' // 定义密钥
app.use(function (req, res, next) {
const { path, method } = req
const token = req.headers.authorization
const pathUnless = [
//白名单,除了这里写的地址,其他的URL都需要验证token
'/',
'/register',
'/login',
{
url: '/articles',
methods: ['GET'],
},
{
url: /^\/articles\/.*/,
urlReg: true, //url是正则
methods: ['GET'],
},
]
//验证请求的地址和方法是否在白名单里
let credentialsRequired = true
pathUnless.forEach((item) => {
if (item === path) {
credentialsRequired = false
}
if (item.url && item.methods) {
//判断url是否正则形式,如果是判断请求的地址是否符合正则
let regPass = item.urlReg && new RegExp(item.url).test(path)
if ((item.url === path || regPass) && item.methods.indexOf(method) > -1) {
credentialsRequired = false
}
}
})
if (!credentialsRequired) {
//不需要进行验证
return next()
} else {
jwt.verify(token, secret, (err, decoded) => {
if (err) {
console.log(err)
return res.json({
msg: 'token无效,请重新登录',
tokenOut: true,
code: 400,
})
// return next() // err放行,会进入错误处理中间件
} else {
console.log('token认证通过,解析结果')
console.log(decoded)
return next() // success放行,会进入router中间件
}
})
}
})
错误中间件
app.use(function (err, req, res, next) {
//判断token是否无效并返回前台
console.log('handle err------------error-----------')
console.log(err)
if (err.name == 'TokenExpiredError') {
//token过期
return res.json({
msg: 'token过期,请重新登录',
tokenOut: true,
code: 400,
})
} else if (err.name == 'JsonWebTokenError') {
//无效的token
return res.json({
msg: 'token无效,请重新登录',
tokenOut: true,
code: 400,
})
}
res.status(err.status || 500)
res.render('error')
})
express 解析并接收 FormData 表单数据
安装 FormData 解析中间件
npm -i express-formidable
const formidable = require('express-formidable') //引入中间件
app.use(formidable()) // 挂载中间件
router.post('/xx', (req, res, next) => {
// 接收formData中的参数
console.log(req.fields)
// 接收formData中的文件
console.log(req.files)
})
前后端交互
express 接收 GET 请求参数
query 参数
前端传 query 参数的两种方式: 1.在请求 url 中直接拼接 ?name=zhangsan 最为参数 2.组装 query 对象
const queryParams = { name: 'zhangsan' }
this.axios.get('/userInfo', queryParams).then((res) => {
console.log(res)
})
this.$axios({
method: 'get',
url: '/userInfo',
params: {
name: 'zhangsan',
},
})
后端接收 query 参数
app.get('/userInfo', (req, res) => {
// http://127.0.0.1/userInfo?name=zhangsan
res.send(req.query)
})
params 参数
前端传 params 参数
this.axios.get('/userInfo/${userId}').then((res) => {
console.log(res)
})
后端接收 params 参数
app.get('/user/:id', (req, res) => {
// http://127.0.0.1/userInfo/5
res.send(req.params)
})
express 接收 post 请求参数
前端传递 data 参数
const data = { name: 'zhangsan' }
this.$axios.post('/user', data).then((res) => {
console.log(res)
})
this.$axios({
method: 'post',
url: '/user',
data: {
name: 'zhangsan',
},
})
后端接收 data 参数
app.post('/form', (req, res) => {
res.send(req.body)
})