玩命加载中🤣🤣🤣

NodeJs-04-express


NodeJS-04-express

基础操作

服务启动

import express from 'express'

const app = express()

app.get('/', (req, res) => {
  res.send('Hello, World!')
})

app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

获取请求参数

import express from 'express'

const app = express()

app.get('/login', (req, res) => {
  // 获取请求参数
  const username = req.query.username
  const password = req.query.password
  // 校验参数
  if (!username || !password) {
    return res.send('username or password is empty')
  }
  res.send(`welcome 【${username}`)
  console.log('用户登录参数: ', username, password)
  // 获取请求头
  const userAgent = req.headers['user-agent']
  console.log('用户登录请求头: ', userAgent)
})


app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

获取路由参数

import express from 'express'

const app = express()

// 获取路由参数
app.get('/shop/:id', (req, res) => {
  const shopId = req.params.id
  res.send(`shop id is 【${shopId}`)
})

app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

响应设置

import express from 'express'

const app = express()

// 响应设置
app.get('/resp', (req, res) => {
  // express 响应 支持链式编程
  res.status(200) // 设置响应状态码
  res.set('Content-Type', 'text/plain') // 设置响应头
  res.send('response body') // 设置响应体
})

app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

其他响应体

import express from 'express'

const app = express()

app.get('/resp-other', (req, res) => {
  res.json({ name: 'express' }) // 发送 JSON 响应
  res.redirect('http://www.baidu.com') // 重定向
  res.download('./package.json') // 下载文件
  res.sendFile(__dirname + '/index.html') // 响应文件内容
})

app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

express中间件

概念

在 Express 框架中,中间件(Middleware) 是其核心概念之一,它指的是一个在请求(Request)到达最终的路由处理函数之前,以及响应(Response)返回给客户端之前,可以被调用的特殊函数。

这些函数可以访问请求对象 (req)、响应对象 (res) 和应用程序中的下一个中间件函数 (next)

本质是一个回调函数

中间件的主要功能包括执行任何代码、修改请求和响应对象、终结请求-响应循环、调用下一个中间件等。根据其作用范围,主要可以分为:

  • 全局中间件
  • 路由中间件
Express 概念 核心特点 Java 中的近似对应 对应关系说明
全局中间件 通过 app.use()注册,对所有进入服务器的请求生效 Servlet 过滤器 (Filter) 两者均在请求处理链的最外层工作,对所有请求进行预处理(如日志、鉴权)和后处理
路由中间件 通过路由方法(如 app.get(), app.post())或路由级 Router 绑定,对特定路由生效 Spring 拦截器 (Interceptor) / AOP 切面 两者都能更精细地控制拦截范围(特定URL、Controller方法),实现权限检查、日志记录等业务逻辑

🛠️ 实践建议

  1. 注册顺序很重要:中间件的注册顺序决定了它们的执行顺序。例如,通常需要将日志记录、CORS 处理等中间件放在最前面,而错误处理中间件必须放在所有路由之后。
  2. 避免阻塞:在编写中间件时,要确保逻辑高效,避免长时间同步操作阻塞事件循环,从而影响服务器性能。
  3. 灵活组合:在实际项目中,可以根据需求灵活组合使用全局中间件和路由中间件。例如,使用全局中间件进行基础安全防护和日志记录,对特定的管理后台路由使用路由中间件进行更严格的身份验证。

代码示例

import express from 'express'
import fs from 'fs'

const app = express()

// 全局中间件:中间件应该放在路由之前定义
app.use(function (req, res, next) {
  let { url, ip } = req
  fs.appendFile('./log.txt', `${url}   ${ip}\n`, (err) => {
    if (err) {
      console.log('写入日志失败', err)
    }
  })
  next()
})

// 路由中间件:在处理函数之前执行
let checkCodeMiddleware = (req, res, next) => {
  // 判断请求参数中是否包含code参数
  let { code } = req.query
  if (!code) {
    return res.send('code is empty')
  }
  next()
}

// 路由中间件:在处理函数之前执行
app.get('/home', checkCodeMiddleware, (req, res) => {
  res.send('前台首页')
})

// 路由中间件:在处理函数之前执行
app.get('/admin', checkCodeMiddleware, (req, res) => {
  res.send('后台首页')
})

// 使用app.use处理404页面,确保放在所有路由之后
app.use((req, res) => {
  res.status(404).send('<h1>404 Not Found</h1>')
})

app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

静态资源中间件

通过一行代码搞定:

app.use(express.static(__dirname + '/public'))

静态资源示例代码

import express from 'express'
import path from 'path'
import { fileURLToPath } from 'url'

const app = express()

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

// 静态资源中间件:将public目录下的文件作为静态资源提供
app.use(express.static(__dirname + '/public'))
app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

注意事项

  1. index.html 文件为默认打开的资源
  2. 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
  3. 路由响应动态资源,静态资源中间件响应静态资源

express获取请求体的中间件

核心使用内置中间件:

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

app.use(express.json())

import express from 'express'

const app = express()

// 在Express 5.x中,建议全局使用这些中间件
// 对于表单数据 (application/x-www-form-urlencoded)
app.use(express.urlencoded({ extended: false }))
// 对于JSON数据 (application/json)
app.use(express.json())

app.post('/register', (req, res) => {
  const body = req.body
  console.log('注册参数: ', body)
  res.send('register success')
})

app.post('/save', (req, res) => {
  const body = req.body
  console.log('保存参数: ', body)
  res.send('save success')
})

// 添加一个简单的表单页面用于测试
app.get('/form', (req, res) => {
  res.send(`
    <form action="/save" method="post">
      <label>姓名: <input type="text" name="name"></label><br>
      <label>邮箱: <input type="email" name="email"></label><br>
      <button type="submit">提交</button>
    </form>
  `)
})

app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

路由

概念

express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象。

作用

对路由进行模块化,更好的管理路由

示例

先封装路由

// ./router/home.js

import express from 'express'

const router = express.Router()

// 定义首页路由
router.get('/', (req, res) => {
  res.send('<h1>首页</h1>')
})

// 定义登录路由
router.get('/login', (req, res) => {
  res.send('<h1>登录页</h1>')
})

// 导出路由模块
export default router

服务中引用

import express from 'express'
import homeRouter from './router/home.js'

const app = express()
app.use('/', homeRouter)
app.use('/user', homeRouter)// 内部的路由会自动添加前缀,类似java的@RequestMapping("/users")

app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

EJS模板引擎

初体验

import ejs from 'ejs'

let person = ['张三', '李四', '王五']

let html = ejs.render('<%= person.join(",") %>', { person })
console.log(html)

express使用模板引擎

  • 构建模板文件夹及模板引擎,注意模板引擎拓展名是 ejs,如:./views/user.ejs
  • 服务端
    • 设置模板引擎为 EJS
    • 指定模板目录
    • 渲染数据
  • 引擎基础语法
    • <%= %> 语法输出变量值
    • 使用 <% %> 包裹 JavaScript 代码逻辑

代码示例:

ejs文件:./views/user.ejs

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <h2><%= title %></h2>
  <h3>学生列表</h3>
  <!-- 条件判断 -->
  <% if (hasRegister) { %>
    <p>用户已注册</p>
  <% } else { %>
    <p>用户未注册</p>
  <% } %>

  <table border="1" cellpadding="5">
    <tr>
      <th>姓名</th>
      <th>年龄</th>
    </tr>
    <!-- 控制结构 -->
    <% person.forEach(item => { %>  
      <tr>
        <!-- 输出变量 -->
        <td><%= item.name %></td>
        <td><%= item.age %></td>
      </tr>
    <% }) %>
  </table>
</body>

</html>

服务端

import express from 'express'
import path from 'path'

const app = express()
// 设置模板引擎为 EJS
app.set('view engine', 'ejs')
// 设置模板文件存放位置 注意:ES6模块中一定要用全路径
app.set('views', path.join(import.meta.dirname, './views'))

let person = [
  { name: '张三', age: 18 },
  { name: '李四', age: 20 },
  { name: '王五', age: 22 }
]

let hasRegister = true

app.get('/user', (req, res) => {
  res.render('user', { person, title: '用户列表(我是EJS渲染数据)', hasRegister })
})

app.listen(9999, () => {
  console.log('Server is running on port 9999')
})

generator工具

初始化

安装

npm i -g express-generator

使用

express -e # 新建脚手架

yarn # 安装依赖

yarn start # 跑项目

# 访问端口 3000

使用 npx 创建

npx express-generaor -e

文件上传

以头像上传为例:

前端部分

  • 添加路由
router.get('/portrait', (req, res) => {
  res.render('portrait')
})
  • 模板构建 views/portrait.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h2>用户头像</h2>
  <form action="/portrait" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username" required><br/>
    头像:<input type="file" name="avator" required><br/>
    <input type="submit" value="上传">
  </form>
</body>
</html>

后端部分

  • 安装依赖 npm i formidable / yarn add formidable
  • 添加路由
var { formidable } = require('formidable'); // 注意:v3.x版本中它不再直接导出一个函数,而是导出一个对象

router.post('/portrait', (req, res, next) => {
  // 创建表单对象
  const form = formidable({
    multiples: true,
    uploadDir: __dirname + '/../public/images', // 指定上传地址
    keepExtensions: true, // 是否保持扩展名
  })
  // 解析请求报文
  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }
    console.log(fields, files);
    let fileUrl = '/images/' + files.avator[0].newFilename;
    // 响应
    res.send(fileUrl);
  });
});

ts构建工具

npx express-generator-typescript 项目名
cd 项目文件夹
git init .

文章作者: 👑Dee👑
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 👑Dee👑 !
  目录