mkdir api-start
cd api-start
pnpm i koa
mkdir src && touch ./src/index.js编写 index.js 文件
const Koa = require("koa")
const app = new Koa()
app.use(async (ctx) => {
ctx.body = "Hello World"
})
app.listen(3000, () => {
console.log("Server is running on http://localhost:3000")
})pnpm i @koa/router修改 src/index.js
const Koa = require("koa")
const Router = require("@koa/router")
const app = new Koa()
const router = new Router()
router.get("/", (ctx) => {
ctx.body = "Hello World"
})
router.get("/api", (ctx) => {
ctx.body = "Hello api"
})
router.get("/async", async (ctx) => {
let result = await new Promise((resolve) => {
setTimeout(function () {
resolve("Hello async")
}, 2000)
})
ctx.body = result
})
// 添加路由
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000, () => {
console.log("Server is running on http://localhost:3000")
})pnpm i koa-body @koa/cors修改 src/index.js
const Koa = require("koa")
const Router = require("@koa/router")
const cors = require("@koa/cors")
const { koaBody } = require("koa-body")
const app = new Koa()
const router = new Router()
router.get("/", (ctx) => {
ctx.body = "Hello World"
})
router.get("/api", (ctx) => {
ctx.body = "Hello api"
})
router.get("/async", async (ctx) => {
let result = await new Promise((resolve) => {
setTimeout(function () {
resolve("Hello async")
}, 2000)
})
ctx.body = result
})
router.post("/post", (ctx) => {
let { body } = ctx.request
ctx.body = body
})
// 注意插件的顺序
app.use(koaBody())
app.use(cors())
// 添加路由
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000, () => {
console.log("Server is running on http://localhost:3000")
})koa-json 自动将响应对象转换为 JSON 格式
pnpm i koa-jsonKoa 应用中引入并使用 koa-json 中间件:
const Koa = require('koa');
const json = require('koa-json');
const app = new Koa();
// 使用 koa-json 中间件
app.use(json());
app.use('/api',async (ctx) => {
ctx.body = { message: 'Hello World' };
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});可以在使用 koa-json 时传递配置选项,例如:app.use(json({ pretty: false, param: 'pretty' }));
pretty: 是否格式化输出,默认为 trueparam: 当请求 URL 中包含指定参数时,强制格式化输出访问 http://localhost:3000/api?pretty
koa-helmet 是一个用于 Koa 框架的中间件插件,通过设置各种 HTTP 头来帮助增强你的应用程序的安全性。koa-helmet 是 helmet 的 Koa 版本,helmet 是一个用于 Express 的安全中间件
pnpm i koa-helmetKoa 应用中引入并使用 koa-helmet 中间件:
const Koa = require('koa');
const helmet = require('koa-helmet');
const app = new Koa();
// 使用 koa-helmet 中间件
app.use(helmet());
app.use(async (ctx) => {
ctx.body = 'Hello World';
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});koa-helmet 通过设置以下 HTTP 头来增强安全性:
Content-Security-Policy: 防止跨站脚本攻击(XSS)和其他跨站点注入攻击X-DNS-Prefetch-Control: 控制浏览器的 DNS 预取行为Expect-CT: 防止中间人攻击Strict-Transport-Security: 强制使用 HTTPSX-Frame-Options: 防止点击劫持X-Content-Type-Options: 防止 MIME 类型嗅探X-Permitted-Cross-Domain-Policies: 控制 Adobe Flash 和 Acrobat 的跨域策略Referrer-Policy: 控制 Referer 头的内容X-XSS-Protection: 启用浏览器的 XSS 过滤器可以根据需要配置 koa-helmet,例如:
app.use(helmet({
contentSecurityPolicy: false, // 禁用 Content-Security-Policy 头
frameguard: {
action: 'deny' // 设置 X-Frame-Options 头为 'deny'
}
}));koa-static 是一个用于 Koa 框架的中间件插件,它可以用来提供静态文件服务,例如 HTML、CSS、JavaScript 文件以及图片等
pnpm install koa-static使用
const Koa = require('koa');
const statics = require('koa-static');
const app = new Koa();
// 使用 koa-static 中间件,提供静态文件服务
app.use(statics(path.join(__dirname, 'public')));
app.listen(3000, () => {
console.log("Server is running on http://localhost:3000");
});可以在使用 koa-static 时传递配置选项,例如:
app.use(serve(path.join(__dirname, 'public'), {
maxage: 86400000, // 设置缓存时间,单位为毫秒
hidden: true, // 允许访问隐藏文件
index: 'index.html', // 默认文件
gzip: true // 启用 gzip 压缩
}));maxage: 设置缓存时间,单位为毫秒hidden: 是否允许访问隐藏文件(以 . 开头的文件)index: 默认文件名gzip: 是否启用 gzip 压缩将多个中间件函数组合成一个单一的中间件函数。保持中间件的执行顺序。适用于复杂的中间件逻辑管理。
pnpm i koa-compose使用
import Koa from "koa"
import Router from "@koa/router"
import cors from "@koa/cors"
import { koaBody } from "koa-body"
import json from "koa-json"
import helmet from "koa-helmet"
import statics from "koa-static"
import path from "path"
import compose from "koa-compose"
const app = new Koa()
const router = new Router()
// router.prefix("/api")
router.get("/api", (ctx) => {
ctx.body = {
name: "koa2",
version: "2.13.0"
}
})
router.post("/post", (ctx) => {
let { body } = ctx.request
ctx.body = body
})
const middleware = compose([koaBody(), statics(path.join(__dirname, "../public")), cors(), json(), helmet()])
app.use(middleware)
// 添加路由
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000, () => {
console.log("Server is running on http://localhost:3000")
})koa-compress 是一个用于 Koa 框架的中间件插件,它可以对 HTTP 响应进行压缩,以减少传输的数据量,提高应用的性能。koa-compress 支持多种压缩算法,包括 gzip 和 brotli
pnpm install koa-compress使用:
const Koa = require('koa');
const compress = require('koa-compress');
const app = new Koa();
// 使用 koa-compress 中间件
app.use(compress());
app.use(async (ctx) => {
ctx.body = 'Hello World';
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});Accept-Encoding 头选择合适的压缩算法。可以在使用 koa-compress 时传递配置选项,例如:
filter: 一个函数,用于过滤哪些响应需要压缩。默认情况下,所有类型的响应都会被压缩threshold: 只有大于这个字节数的响应才会被压缩。默认值为 1024gzip: 配置 gzip 压缩的选项brotli: 配置 brotli 压缩的选项deflate: 配置 deflate 压缩的选项app.use(compress({
filter: (content_type) => {
return /text/i.test(content_type);
},
threshold: 2048, // 只有大于 2048 字节的响应才会被压缩
gzip: {
flush: require('zlib').constants.Z_SYNC_FLUSH
},
brotli: {
flush: require('zlib').constants.BROTLI_OPERATION_FLUSH
},
deflate: {
flush: require('zlib').constants.Z_SYNC_FLUSH,
}
}));# 局部安装
pnpm i -D nodemon
npx nodemon ./index.jspnpm i webpack webpack-cli -D
# windows 上 @babel/node 要全局安装
pnpm i clean-webpack-plugin webpack-node-externals @babel/core @babel/node @babel/preset-env babel-loader cross-env -D新建 .babelrc 文件
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}在根目录创建 webpack.config.js 文件
const path = require("path")
const nodeExternals = require("webpack-node-externals")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const webpackConfig = {
target: "node",
mode: "development",
devtool: "eval-source-map",
entry: {
server: path.join(__dirname, "src/index.js")
},
output: {
filename: "[name].bundle.js",
path: path.join(__dirname, "dist")
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
},
exclude: [path.join(__dirname, "node_modules")]
}
]
},
externals: [nodeExternals()],
plugins: [new CleanWebpackPlugin()],
node: {
__dirname: true,
__filename: true,
global: true
}
}
module.exports = webpackConfig终端运行 npx webpack 命令打包
修改 src/index.js 文件
// const Koa = require("koa")
// const Router = require("@koa/router")
// const cors = require("@koa/cors")
// const { koaBody } = require("koa-body")
// const json = require("koa-json")
import Koa from "koa"
import Router from "@koa/router"
import cors from "@koa/cors"
import { koaBody } from "koa-body"
import json from "koa-json"# 修改前
nodemon ./src/index.js
# 修改后
npx babel-node src/index.js
# 添加热加载
npx nodemon --exec babel-node src/index.jsnode --inspect-brk ./node_modules/.bin/webpack --inline --progress
# Debugger listening on ws://127.0.0.1:9229/6eb6ad8b-61b5-472b-b399-928127b595c2
# For help, see: https://nodejs.org/en/docs/inspector打开 Chrome 调试 页面,并点击 inspect 按钮

找到运行与调试、添加配置。在 launch.json 文件中添加运行的配置

launch.json 文件
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "nodemon",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/nodemon",
"program": "${workspaceFolder}/src/index.js",
"restart": true,
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"runtimeArgs": ["--exec", "babel-node"]
}
]
}pnpm i -g npm-check-updates
ncu --help新建 config 文件夹
pnpm i webpack-merge nodemon-webpack-plugin terser-webpack-plugin -Dconfig/webpack.config.base.js
const path = require("path")
const webpack = require("webpack")
const nodeExternals = require("webpack-node-externals")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const webpackConfig = {
target: "node",
entry: {
server: path.join(__dirname, "../src/index.js")
},
output: {
path: path.join(__dirname, "../dist"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: "babel-loader"
},
exclude: [path.join(__dirname, "/node_modules")]
}
]
},
externals: [nodeExternals()],
plugins: [new CleanWebpackPlugin(), new webpack.EnvironmentPlugin(["NODE_ENV"])],
node: {
__dirname: true,
__filename: true
}
}
module.exports = webpackConfigconfig/webpack.config.dev.js
const { merge } = require("webpack-merge")
const NodemonPlugin = require("nodemon-webpack-plugin")
const baseWebpackConfig = require("./webpack.config.base")
const webpackConfig = merge(baseWebpackConfig, {
mode: "development",
devtool: "eval-source-map",
stats: { children: false }, // Hide children information
plugins: [new NodemonPlugin()]
})
module.exports = webpackConfigconfig/webpack.config.prod.js
const { merge } = require("webpack-merge")
const baseWebpackConfig = require("./webpack.config.base")
const TerserWebpackPlugin = require("terser-webpack-plugin")
const webpackConfig = merge(baseWebpackConfig, {
mode: "production",
stats: { children: false, warnings: false },
optimization: {
minimizer: [
new TerserWebpackPlugin({
terserOptions: {
warnings: false,
compress: {
warnings: false,
// 是否注释掉 console
drop_console: false,
dead_code: true,
drop_debugger: true
},
output: {
comments: false,
beautify: false
},
mangle: true
},
parallel: true
})
],
splitChunks: {
cacheGroups: {
commons: {
name: "commons",
chunks: "initial",
minChunks: 3,
enforce: true
}
}
}
}
})
module.exports = webpackConfigpnpm i -D rimraf在 package.json 中添加脚本
{
"scripts": {
"clean": "rimraf dist"
}
}