NodeJS
Web框架
Koa
代码示例:
// index.js
const koa = require('koa')
const app = new koa()
app.use((ctx, next) => {
// 支持省略response与request(不会冲突)
// ctx.response.body = '<h1>Hello World!</h1>'
ctx.response.body = {ok: 1}
// console.log(ctx.request.path)
})
app.listen(3000)
洋葱模型
next可回弹继续执行而不是一直往下执行
代码示例:
// index.js
const koa = require('koa')
const app = new koa()
app.use(async (ctx, next) => {
if (ctx.url === '/favicon.ico') return
console.log('aaa')
const token = await next()
console.log('ddd', token)
ctx.body = 'Hello World!'
})
function delay(time) {
return new Promise((resolve, reject) => {
setTimeout(resolve, time)
})
}
app.use(async (ctx, next) => {
console.log('bbb')
await delay(1000)
ctx.token = 'Foo'
console.log('ccc')
return 'Bar'
})
app.listen(3000)
路由
代码示例:
// index.js
const koa = require('koa')
const app = new koa()
const Router = require('koa-router')
const router = new Router()
router.post('/list', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'add list success'
}
})
.get('/list', (ctx, next) => { // 链式写法
ctx.body = ['aaa', 'bbb', 'ccc']
})
.put('/list/:id', (ctx, next) => {
// console.log(ctx.params)
ctx.body = {
ok: 1,
info: 'put list success'
}
})
.delete('/list/:id', (ctx, next) => {
// console.log(ctx.params)
ctx.body = {
ok: 1,
info: 'delete list success'
}
})
app.use(router.routes()).use(router.allowedMethods()) // 第二个use:仅响应相应的请求,如果出现其它的请求则返回405而不是404
app.listen(3000)
拆分路由
代码示例:
// index.js
const koa = require('koa')
const app = new koa()
const router = require('./routes') // index可以省略
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
// routes/index.js
const Router = require('koa-router')
const router = new Router()
const userRouter = require('./user')
const listRouter = require('./list')
const homeRouter = require('./home')
// router.prefix('/api') // 统一配置前缀
// 注册成路由级的组件(或中间件)
router.use('/user', userRouter.routes(), userRouter.allowedMethods())
router.use('/list', listRouter.routes(), listRouter.allowedMethods())
router.use('/home', homeRouter.routes(), homeRouter.allowedMethods())
router.redirect('/', '/home') // 重定向
module.exports = router
// routes/home.js
const Router = require("koa-router");
const router = new Router()
router.get('/', (ctx, next) => {
ctx.body = `
<h1>h1</h1>
`
})
module.exports = router
// routes/user.js
const Router = require("koa-router");
const router = new Router()
router.post('/', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'add user success'
}
})
.get('/', (ctx, next) => {
ctx.body = ['aaa', 'bbb', 'ccc']
})
.put('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'put user success'
}
})
.delete('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'delete user success'
}
})
module.exports = router
// routes/list.js
const Router = require("koa-router");
const router = new Router()
router.post('/', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'add list success'
}
})
.get('/', (ctx, next) => {
ctx.body = ['aaa', 'bbb', 'ccc']
})
.put('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'put list success'
}
})
.delete('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'delete list success'
}
})
module.exports = router
静态资源
代码示例:
/* public/css/center.css */
div {
background-color: #30363d;
}
// index.js
const koa = require('koa')
const app = new koa()
const koaStatic = require('koa-static')
const path = require('path')
const router = require('./routes')
app.use(koaStatic(path.join(__dirname, 'public')))
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
<!-- public/center.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Center</title>
<link rel="stylesheet" href="/css/center.css">
</head>
<body>
<div>Center</div>
</body>
</html>
获取请求参数
代码示例:
<!-- static/login.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
用户名:<input type="text" id="useName"/>
</div>
<div>
密码:<input type="password" id="pwd"/>
</div>
<div>
<button id="loginGet">登录-GET</button>
<button id="loginPost">登录-POST</button>
</div>
<script>
// const useName = document.querySelector('#useName')
// const pwd = document.querySelector('#pwd')
// const loginGet = document.querySelector('#loginGet')
// const loginPost = document.querySelector('#loginPost')
// loginGet.onclick = () => {
// fetch(`/user?username=${useName.value}&pwd=${pwd.value}`)
// .then(res => res.text())
// .then(res => console.log(res))
// .catch(err => console.log(err))
// }
// loginPost.onclick = () => {
// fetch(`/user`, {
// method: 'POST',
// body: JSON.stringify({
// usename: useName.value,
// pwd: pwd.value
// }),
// headers: {
// 'Content-Type': 'application/json'
// }
// })
// .then(res => res.text())
// .then(res => console.log(res))
// .catch(err => console.log(err))
// }
const useName = document.querySelector('#useName')
const pwd = document.querySelector('#pwd')
const loginGet = document.querySelector('#loginGet')
const loginPost = document.querySelector('#loginPost')
loginGet.onclick = () => {
fetch(`/user?username=${useName.value}&pwd=${pwd.value}`)
.then(res => res.text())
.then(res => console.log(res))
.catch(err => console.log(err))
}
loginPost.onclick = () => {
fetch(`/user`, {
method: 'POST',
body: `username=${useName.value}&pwd=${pwd.value}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(res => res.text())
.then(res => console.log(res))
.catch(err => console.log(err))
}
</script>
</body>
</html>
// routes/user.js
const Router = require("koa-router");
const router = new Router()
router.post('/', (ctx, next) => {
console.log(ctx.request.body) // 省略掉request是有区别的
ctx.body = {
ok: 1,
info: 'add user success'
}
})
.get('/', (ctx, next) => {
console.log(ctx.query, ctx.querystring)
ctx.body = ['aaa', 'bbb', 'ccc']
})
.put('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'put user success'
}
})
.delete('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'delete user success'
}
})
module.exports = router
// index.js
const koa = require('koa')
const app = new koa()
const koaStatic = require('koa-static')
const path = require('path')
const bodyParser = require('koa-bodyparser')
const router = require('./routes')
app.use(bodyParser()) // 获取POST参数
app.use(koaStatic(path.join(__dirname, 'public')))
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
ejs模板
代码示例:
// index.js
const koa = require('koa')
const app = new koa()
const koaStatic = require('koa-static')
const path = require('path')
const bodyParser = require('koa-bodyparser')
const views = require('koa-views')
const router = require('./routes')
// 配置模板引擎
app.use(views(path.join(__dirname, 'views'), {extension: 'ejs'}))
app.use(bodyParser())
app.use(koaStatic(path.join(__dirname, 'public')))
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
// routes/home.js
const Router = require("koa-router");
const router = new Router()
router.get('/', async (ctx, next) => {
// 必须使用async/await(因为是异步执行的)
await ctx.render('home', {username: 'HQSY'}) // 自动寻找views目录(配置模板引擎时指定的第二个实参)下的home.ejs
})
module.exports = router
<!-- views/home.ejs -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<h1><%= username%></h1>
</body>
</html>
鉴权
Cookie与Session
代码示例:
// routes/home.js
const Router = require("koa-router");
const router = new Router()
router.get('/', async (ctx, next) => {
// ctx.cookies.set('name', 'HQSY')
// console.log(ctx.cookies.get('name'))
await ctx.render('home', {username: 'HQSY'})
})
module.exports = router
// routes/login.js
const Router = require("koa-router");
const router = new Router()
router.get('/', async (ctx, next) => {
await ctx.render('login')
})
module.exports = router
// routes/user.js
const Router = require("koa-router");
const router = new Router()
router.post('/', (ctx, next) => {
console.log(ctx.request.body)
ctx.body = {
ok: 1,
info: 'add user success'
}
})
.get('/', (ctx, next) => {
console.log(ctx.query, ctx.querystring)
ctx.body = ['aaa', 'bbb', 'ccc']
})
.put('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'put user success'
}
})
.delete('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'delete user success'
}
})
router.post('/login', (ctx) => {
// console.log(ctx.request.body)
const {username, pwd} = ctx.request.body
if (username === 'HQSY' && pwd === '123') {
ctx.session.user = {
username: 'HQSY'
}
ctx.body = {ok: 1}
} else {
ctx.body = {ok: 0}
}
})
module.exports = router
// index.js
const koa = require('koa')
const app = new koa()
const koaStatic = require('koa-static')
const path = require('path')
const bodyParser = require('koa-bodyparser')
const views = require('koa-views')
const session = require('koa-session-minimal')
const router = require('./routes')
app.use(views(path.join(__dirname, 'views'), {extension: 'ejs'}))
app.use(session({
key: 'HQSY_Session',
cookie: {
maxAge: 1000 * 60 * 60
}
}))
app.use(async (ctx, next) => {
if (ctx.url.includes('login')) {
await next() // 等待执行权的回弹
return
}
if (ctx.session.user) {
ctx.session.date = Date.now() // 重置有效期
await next()
} else {
ctx.redirect('/login')
}
})
app.use(bodyParser())
app.use(koaStatic(path.join(__dirname, 'public')))
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
<!-- views/login.ejs -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<div>
用户名:<input type="text" id="useName"/>
</div>
<div>
密码:<input type="password" id="pwd"/>
</div>
<div>
<button id="loginPost">登录-POST</button>
</div>
<script>
const useName = document.querySelector('#useName')
const pwd = document.querySelector('#pwd')
const loginPost = document.querySelector('#loginPost')
loginPost.onclick = () => {
fetch(`/user/login`, {
method: 'POST',
body: `username=${useName.value}&pwd=${pwd.value}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(res => res.json())
.then(res => {
if (res.ok === 1) {
location.href = '/home'
} else {
alert('用户名或密码错误!')
}
})
.catch(err => console.log(err))
}
</script>
</body>
</html>
JWT
代码示例:
// routes/home.js
const Router = require("koa-router");
const router = new Router()
router.get('/', async (ctx, next) => {
// ctx.cookies.set('name', 'HQSY')
// console.log(ctx.cookies.get('name'))
await ctx.render('home', {username: 'HQSY'})
})
router.get('/list', async (ctx) => {
ctx.body = [
{
_id: 1,
username: 'Foo',
age: 12
},
{
_id: 2,
username: 'HQSY',
age: 24
},
{
_id: 3,
username: 'Bar',
age: 18
}
]
})
module.exports = router
// routes/user.js
const Router = require("koa-router");
const JWT = require("../util/JWT");
const router = new Router()
router.post('/', (ctx, next) => {
console.log(ctx.request.body)
ctx.body = {
ok: 1,
info: 'add user success'
}
})
.get('/', (ctx, next) => {
console.log(ctx.query, ctx.querystring)
ctx.body = ['aaa', 'bbb', 'ccc']
})
.put('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'put user success'
}
})
.delete('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'delete user success'
}
})
router.post('/login', (ctx) => {
const {username, pwd} = ctx.request.body
if (username === 'HQSY' && pwd === '123') {
const token = JWT.generate({
_id: 'aaa',
username: 'HQSY'
}, '1h')
ctx.set('Authorization', token)
ctx.body = {ok: 1}
} else {
ctx.body = {ok: 0}
}
})
module.exports = router
// index.js
const koa = require('koa')
const app = new koa()
const koaStatic = require('koa-static')
const path = require('path')
const bodyParser = require('koa-bodyparser')
const views = require('koa-views')
const session = require('koa-session-minimal')
const router = require('./routes')
const JWT = require('./util/JWT')
app.use(views(path.join(__dirname, 'views'), {extension: 'ejs'}))
app.use(session({
key: 'HQSY_Session',
cookie: {
maxAge: 1000 * 60 * 60,
}
}))
app.use(async (ctx, next) => {
if (ctx.url.includes('login')) {
await next()
return
}
const token = ctx.headers['authorization']?.split(' ')[1]
if (token) {
const payload = JWT.verify(token)
if (payload) {
const newToken = JWT.generate({
_id: payload._id,
username: payload.username
}, '1h')
ctx.set('Authorization', newToken)
await next()
} else {
ctx.status = 401
ctx.body = {errCode: -1, errInfo: 'token无效'}
}
} else {
await next()
}
})
app.use(bodyParser())
app.use(koaStatic(path.join(__dirname, 'public')))
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)
// util/JWT.js
const jwt = require('jsonwebtoken')
const secret = 'HQSY'
const JWT = {
generate(value, expires) {
return jwt.sign(value, secret, {expiresIn: expires})
},
verify(token) {
try {
return jwt.verify(token, secret)
} catch (err) {
return false
}
}
}
module.exports = JWT
<!-- views/login.ejs -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<div>
<div>用户名:<input type="text" id="username"></div>
<div>密码:<input type="password" id="pwd"></div>
<div><button id="login">登录</button></div>
</div>
<script src="/dist/axios.min.js"></script>
<script>
axios.interceptors.request.use(function (config) {
return config
}, function (error) {
return Promise.reject((error))
})
axios.interceptors.response.use(function (response) {
const {authorization} = response.headers
authorization && localStorage.setItem('token', authorization)
return response
}, function (error) {
return Promise.reject(error)
})
</script>
<script>
const username = document.querySelector('#username')
const pwd = document.querySelector('#pwd')
const login = document.querySelector('#login')
login.onclick = () => {
axios.post('/user/login', {
username: username.value,
pwd: pwd.value
}).then(res => {
if (res.data.ok === 1){
location.href = '/'
} else {
alert('用户名或密码错误!')
}
}).catch(err => console.log(err))
}
</script>
</body>
</html>
<!-- views/home.ejs -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<div>
<div>用户名:<input type="text" id="username"></div>
<div>密码:<input type="password" id="pwd"></div>
<div>年龄:<input type="number" id="age"></div>
<div>头像:<input type="file" id="avatar"></div>
<div><button id="register">添加用户</button></div>
</div>
<table>
<thead>
<tr>
<td>id</td>
<td>用户名</td>
<td>年龄</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div>
<button id="exit">退出登录</button>
</div>
<script src="/dist/axios.min.js"></script>
<script>
axios.interceptors.request.use(function (config) {
const token = localStorage.getItem('token')
config.headers.Authorization = `Bearer ${token}`
return config
}, function (error) {
return Promise.reject((error))
})
axios.interceptors.response.use(function (response) {
const {authorization} = response.headers
authorization && localStorage.setItem('token', authorization)
return response
}, function (error) {
if (error.response.status === 401) {
localStorage.removeItem('token')
location.href = '/login'
}
return Promise.reject(error)
})
</script>
<script>
const register = document.querySelector('#register')
const exit = document.querySelector('#exit')
exit.onclick = () => {
localStorage.removeItem('token')
location.href = '/login'
}
axios.get('/home/list').then(res => {
const tbody = document.querySelector('tbody')
tbody.innerHTML = res.data.map(item => `
<tr>
<td>${item._id}</td>
<td>${item.username}</td>
<td>${item.age}</td>
</tr>
`).join('')
}).catch(err => console.log(err))
</script>
</body>
</html>
文件上传
代码示例:
// routes/index.js
const Router = require('koa-router')
const router = new Router()
const userRouter = require('./user')
const listRouter = require('./list')
const homeRouter = require('./home')
const loginRouter = require('./login')
const uploadRouter = require('./upload')
router.use('/user', userRouter.routes(), userRouter.allowedMethods())
router.use('/list', listRouter.routes(), listRouter.allowedMethods())
router.use('/home', homeRouter.routes(), homeRouter.allowedMethods())
router.use('/login', loginRouter.routes(), loginRouter.allowedMethods())
router.use('/upload', uploadRouter.routes(), uploadRouter.allowedMethods())
router.redirect('/', '/home') // 重定向
module.exports = router
// routes/user.js
const Router = require("koa-router");
const JWT = require("../util/JWT");
const router = new Router()
const multer = require('@koa/multer')
const upload = multer({dest: 'public/uploads'})
router.post('/', (ctx, next) => {
console.log(ctx.request.body)
ctx.body = {
ok: 1,
info: 'add user success'
}
})
.get('/', (ctx, next) => {
console.log(ctx.query, ctx.querystring)
ctx.body = ['aaa', 'bbb', 'ccc']
})
.put('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'put user success'
}
})
.delete('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'delete user success'
}
})
router.post('/login', (ctx) => {
const {username, pwd} = ctx.request.body
if (username === 'HQSY' && pwd === '123') {
const token = JWT.generate({
_id: 'aaa',
username: 'HQSY'
}, '1h')
ctx.set('Authorization', token)
ctx.body = {ok: 1}
} else {
ctx.body = {ok: 0}
}
})
router.post('/upload', upload.single('avatar'), (ctx) => {
console.log(ctx.request.body, ctx.file)
ctx.body = {ok: 1}
})
module.exports = router
// routes/upload.js
const Router = require("koa-router");
const router = new Router()
router.get('/', async (ctx, next) => {
await ctx.render('upload')
})
module.exports = router
<!-- /views/upload.ejs -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Upload</title>
</head>
<body>
<form action="/user/upload" method="POST" enctype="multipart/form-data">
<div>
用户名:<input type="text" name="username"/>
</div>
<div>
密码:<input type="password" name="pwd"/>
</div>
<div>
年龄:<input type="number" name="age"/>
</div>
<div>
头像:<input type="file" name="avatar"/>
</div>
<div>
<input type='submit' value="提交">
</div>
</form>
</body>
</html>
MongoDB
代码示例:
// config/db.config.js
const mongoose = require('mongoose')
mongoose.connect('mongodb://127.0.0.1:27017/test')
// routes/user.js
const Router = require("koa-router");
const JWT = require("../util/JWT");
const router = new Router()
const multer = require('@koa/multer')
const upload = multer({dest: 'public/uploads'})
const UserModel = require('../model/UserModel')
router.post('/', (ctx, next) => {
console.log(ctx.request.body)
ctx.body = {
ok: 1,
info: 'add user success'
}
})
.get('/', (ctx, next) => {
console.log(ctx.query, ctx.querystring)
ctx.body = ['aaa', 'bbb', 'ccc']
})
.put('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'put user success'
}
})
.delete('/:id', (ctx, next) => {
ctx.body = {
ok: 1,
info: 'delete user success'
}
})
router.post('/login', (ctx) => {
const {username, pwd} = ctx.request.body
if (username === 'HQSY' && pwd === '123') {
const token = JWT.generate({
_id: 'aaa',
username: 'HQSY'
}, '1h')
ctx.set('Authorization', token)
ctx.body = {ok: 1}
} else {
ctx.body = {ok: 0}
}
})
router.post('/upload', upload.single('avatar'), async (ctx) => {
// console.log(ctx.request.body, ctx.file)
const {username, age, pwd} = ctx.request.body
const avatar = ctx.file ? `/uploads/${ctx.file.filename}` : `默认头像.png`
await UserModel.create({
username,
age,
pwd,
avatar
})
ctx.body = {ok: 1}
})
module.exports = router
// model/UserModel.js
const mongoose = require('mongoose')
const UserType = {
username: String,
pwd: String,
age: Number,
avatar: String
}
const Schema = new mongoose.Schema(UserType)
const UserModel = mongoose.model('user', Schema)
module.exports = UserModel
// index.js
const koa = require('koa')
const app = new koa()
const koaStatic = require('koa-static')
const path = require('path')
const bodyParser = require('koa-bodyparser')
const views = require('koa-views')
const session = require('koa-session-minimal')
const router = require('./routes')
const JWT = require('./util/JWT')
require('./config/db.config')
app.use(views(path.join(__dirname, 'views'), {extension: 'ejs'}))
app.use(session({
key: 'HQSY_Session',
cookie: {
maxAge: 1000 * 60 * 60,
}
}))
app.use(async (ctx, next) => {
if (ctx.url.includes('login')) {
await next()
return
}
const token = ctx.headers['authorization']?.split(' ')[1]
if (token) {
const payload = JWT.verify(token)
if (payload) {
const newToken = JWT.generate({
_id: payload._id,
username: payload.username
}, '1h')
ctx.set('Authorization', newToken)
await next()
} else {
ctx.status = 401
ctx.body = {errCode: -1, errInfo: 'token无效'}
}
} else {
await next()
}
})
app.use(bodyParser())
app.use(koaStatic(path.join(__dirname, 'public')))
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)