NodeJS

Web框架

Express

代码示例:

// index.js

const express = require('express')

const app = express()

app.get('/', (req, res) => {
    // res.send('Hello World!')
    // res.send(`
    // <html lang="zh-CN">
    //     <h1>h1</h1>
    // </html>
    // `)
    res.send({
        name: 'HQSY',
        age: 24
    })
})
app.get('/login', (req, res) => {
    res.write('login')
    res.end()
})

app.listen(3000, () => {
    console.log('server start')
})

路由

代码示例:

// index.js

const express = require('express')

const app = express()

app.get('/ab?cd', (req, res) => {
    res.send('ok')  // ?:可选的
})

app.get('/abc/:foo/:bar', (req, res) => {
    res.send('ok')  // 占位符
})

app.get('/ab+cd', (req, res) => {
    res.send('ok')  // +:一个或以上
})

app.get('/ab*cd', (req, res) => {
    res.send('ok')  // *:任意多个字符
})

app.get('/ab(cd)?e', (req, res) => {
    res.send('ok')  // ()?:存在或不存在
})

// 正则表达式写法
app.get(/.*foo$/,(req, res) => {
    res.send('ok')
})

app.listen(3000, () => {
    console.log('server start')
})

基本中间件

代码示例:

// index.js

const express = require('express')

const app = express()

// 第一种写法
app.get('/home', (req, res, next) => {
    const isValid = true  // 模拟验证
    isValid ? next() : res.send('error')  // next():是否继续执行下一个中间件(回调函数)
}, (req, res) => {
    res.send({list: [1, 2, 3]})
})

app.listen(3000, () => {
    console.log('server start')
})
// index.js

const express = require('express')

const app = express()

const func01 = (req, res, next) => {
    const isValid = true
    isValid ? next() : res.send('error')  // 把next()写在send()后面时next()并不会被执行
    // 要想把第一个中间件的执行结构传递给第二个中间件,可以在next()之前配置
}

const func02 = (req, res) => {
    res.send({list: [1, 2, 3]})
}

// 第二种写法
app.get('/home', [func01, func02])
app.get('/list', [func01], (req, res) => {
    res.send({list: [1, 2, 3]})
})

app.listen(3000, () => {
    console.log('server start')
})

应用级中间件

代码示例:

// index.js

// 凡是挂在app下的方法都是应用级别的中间件
const express = require('express')

const app = express()

const func01 = (req, res, next) => {
    const isValid = true
    isValid ? next() : res.send('error')
}

const func02 = (req, res) => {
    res.send({list: [1, 2, 3]})
}

// app.use(func01)  // 以下的路由都会触发func01
app.use('/list', func01)

app.get('/home', [func02])
app.get('/list', (req, res) => {
    res.send({list: [1, 2, 3]})
})

app.listen(3000, () => {
    console.log('server start')
})

路由级中间件

代码示例:

// index.js

const express = require('express')
const app = express()
const {router} = require('./router/IndexRouter')

app.use('/', router)

app.listen(3000, () => {
    console.log('server start')
})
// router/IndexRouter.js

// 凡是挂在router下的方法都是应用级别的中间件
const express = require('express')
const router = express.Router()

router.get('/home', (req, res) => {
    res.send('ok')
})

router.get('/login', (req, res) => {
    res.send('ok')
})

module.exports = {
    router
}
// index.js

// 第二种写法
const express = require('express')
const app = express()
const HomeRouter = require('./router/HomeRouter')
const LoginRouter = require('./router/LoginRouter')

app.use('/home', HomeRouter)
app.use('/login', LoginRouter)

app.listen(3000, () => {
    console.log('server start')
})
// router/HomeRouter.js

const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {
    res.send('ok')
})

module.exports = router
// router/LoginRouter.js

const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {
    res.send('ok')
})

module.exports = router

错误处理中间件

代码示例:

// index.js

const express = require('express')
const app = express()
const HomeRouter = require('./router/HomeRouter')
const LoginRouter = require('./router/LoginRouter')

app.use('/home', HomeRouter)
app.use('/login', LoginRouter)

app.use((err, req, res, next) => {
    res.status(404).send('找不到页面')  // 必须放到最后面
})

app.listen(3000, () => {
    console.log('server start')
})

内置中间件

代码示例:

// index.js

const express = require('express')
const app = express()
const HomeRouter = require('./router/HomeRouter')
const LoginRouter = require('./router/LoginRouter')

// 解析post参数
app.use(express.urlencoded({extended: false}))  // form
app.use(express.json())  // json

app.use('/home', HomeRouter)
app.use('/login', LoginRouter)

app.listen(3000, () => {
    console.log('server start')
})
// router/LoginRouter.js

const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {
    // console.log(req.query)
    res.send('ok')
})

router.post('/', (req, res) => {
    console.log(req.body)  // 必须配置中间件
    res.send({ok: 1})
})

module.exports = router

静态资源

代码示例:

// index.js

const express = require('express')
const app = express()
const HomeRouter = require('./router/HomeRouter')
const LoginRouter = require('./router/LoginRouter')

// 配置静态资源
app.use(express.static('public'))
// app.use('/public',express.static('public'))

app.use(express.urlencoded({extended: false}))
app.use(express.json())

app.use('/home', HomeRouter)
app.use('/login', LoginRouter)

app.listen(3000, () => {
    console.log('server start')
})
// router/LoginRouter.js

const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {
    console.log(req.query)
    res.send('ok')
})

router.post('/', (req, res) => {
    console.log(req.body)
    const {username, pwd} = req.body
    if (username === 'username' && pwd === 'password') {
        res.send({ok: 1})
    } else {
        res.send({ok: 0})
    }
})

module.exports = router
/* public/css/home.css */

div {
   background-color: #30363d;
}
<!-- public/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(`/login?username=${useName.value}&pwd=${pwd.value}`)
                .then(res => res.text())
                .then(res => console.log(res))
                .catch(err => console.log(err))
        }
        loginPost.onclick = () => {
            fetch(`/login`, {
                method: 'POST',
                body: JSON.stringify({
                    username: useName.value,
                    pwd: pwd.value
                }),
                headers: {
                    'Content-Type': 'application/json'
                }
            })
                .then(res => res.json())
                .then(res => {
                    console.log(res)
                    if (res.ok === 1) {
                        location.href = '/home.html'
                    } else {
                        window.alert('用户名或密码错误错误')
                    }
                })
                .catch(err => console.log(err))
        }
    </script>
</body>
</html>
<!-- public/home.html -->

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/css/home.css">
</head>
<body>
    <div>
        欢迎回来
    </div>
</body>
</html>

服务端与客户端渲染

代码示例:

// index.js

const express = require('express')
const app = express()
const HomeRouter = require('./router/HomeRouter')
const LoginRouter = require('./router/LoginRouter')

// 配置模板引擎
app.set('views', './views')
app.set('view engine', 'ejs')
// app.set('view engine', 'html')
// app.engine('html', require('ejs').renderFile)  // 指定HTML模板是用EJS语法解析

app.use(express.static('public'))

app.use(express.urlencoded({extended: false}))
app.use(express.json())

app.use('/home', HomeRouter)
app.use('/login', LoginRouter)

app.listen(3000, () => {
    console.log('server start')
})
// router/LoginRouter.js

const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {
    // send方法可以是HTML片段或JSON
    // json方法只能是JSON
    res.render('login', {error: '', isShow: false})  // 渲染模板后返出给前端(会根据配置寻找views文件夹下的login.ejs)
})

router.post('/', (req, res) => {
    if (req.body.username === 'username' && req.body.pwd === 'password') {
        res.redirect('/home')
    } else {
        res.render('login', {error: '用户名或密码错误!', isShow: true})
    }
})

module.exports = router
// router/HomeRouter.js

const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {
    res.render('home', {list: ['aaa', 'bbb', 'ccc'], html: '<h1>h1</h1>'})
})

module.exports = router
<!-- views/login.ejs -->

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login" method="POST">
        <div>
            用户名:<input type="text" name="username">
        </div>
        <div>
            密码:<input type="password" name="pwd">
        </div>
        <div>
            <input type="submit" value="登录">
        </div>
    </form>
    <p><%=error%></p>
    <p><%=isShow?'用户名或密码错误': ''%></p>
</body>
</html>
<!-- views/home.ejs -->

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <%- include('./header.ejs', {isShowTitle: false})%>
    <ul>
        <%for (let i = 0; i < list.length; i++) {%>
            <li><%= list[i]%></li>
        <%}%>
    </ul>
    <div><%- html%></div>
    <%# 注释(并不会显示在前端的页面源码中)%>
</body>
</html>
<!-- views/header.ejs -->

<header>
    <% if (isShowTitle) {%>
        <h1>h1</h1>
    <%}%>
    <h2>h2</h2>
</header>