koa

# koa

# 安装

npm i koa

# 使用

# 创建服务器

const koa = require("koa");

const app = new koa();

app.use((ctx, next) => {
    console.log(1);
    ctx.body = "hello";
    next();
});

app.use((ctx, next) => {
    console.log(2);
    ctx.body += " world";
});

app.listen(8080);

# api 中间件

const koa = require("koa");

const app = new koa();

app.use((ctx, next) => {
    // console.log(ctx);
    // let name = 'jack'
    // ctx.state.name = name

    // ctx.throw(404, '出错了', {a: 1})

    console.log(ctx.request);

    next();
});

app.use((ctx, next) => {
    // throw new Error();
    // console.log(ctx.state.name);

    ctx.response.body = { name: "jack" };
});

app.on("error", (err) => {
    console.log(err);
});

app.listen(8080);

# koa-static-cache

npm i koa-static-cache
const path = require("path");
const koa = require("koa");
const koaStaticCache = require("koa-static-cache");

const app = new koa();

app.use(
    koaStaticCache(path.join(__dirname, "static"), {
        prefix: "/public",
    })
);

app.use(
    koaStaticCache(path.join(__dirname, "static/img"), {
        prefix: "/img",
    })
);

app.use((ctx, next) => {
    ctx.body = "hello";
});

app.listen(8088);

# koa-router

npm koa-router
const koa = require("koa");
const koaRouter = require("koa-router");

const app = new koa();
const router = new koaRouter();

// app.use((ctx, next) => {
//     console.log(ctx.URL);
//     ctx.body = 'hello'
// })

// router.get('/user', (ctx, next) => {
//     ctx.body = 'user-get';
// })

// 路由嵌套 方式一
const userRouter = new koaRouter();
userRouter.get("/", (ctx, next) => {
    ctx.body = "user-get";
});
userRouter.get("/info", (ctx, next) => {
    ctx.body = "user-info";
});
router.use("/user", userRouter.routes());

// 路由嵌套 方式二
const indexRouter = new koaRouter({
    prefix: "/index",
});
indexRouter.get("/", (ctx, next) => {
    ctx.body = "index-get";
});
indexRouter.get("/add", (ctx, next) => {
    ctx.body = "index/add-get";
});

// 动态路由
const dynamicRouter = new koaRouter();
dynamicRouter.get("/dynamic/:id", (ctx, next) => {
    ctx.body = `dynamic - ${ctx.params.id}`;
});

router.get("/", (ctx, next) => {
    ctx.body = "首页";
});

app.use(router.routes());
app.use(indexRouter.routes());
app.use(dynamicRouter.routes());

app.listen(8088, "localhost");

# koa-bodyparser

npm i koa-bodyparser
const koa = require("koa");
const Router = require("koa-router");
const bodyParser = require("koa-bodyparser");

const app = new koa();

app.use(bodyParser());

const router = new Router();
router.get("/", async (ctx) => {
    ctx.body = "hello";
});
router.post("/change", (ctx) => {
    let { id, name, price, number } = ctx.request.body;
    console.log({ id, name, price, number });
});

app.use(router.routes());

app.listen(8088);

# koa-swig

npm i koa-swig co
const koa = require("koa");
const koaRouter = require("koa-router");
const Swig = require("koa-swig");
const co = require("co");

const render = Swig({
    root: __dirname + "/view", // 模板存放目录
    autoescape: true, // 是否自动escape编码
    cache: false, // 是否启用缓存,开发时可以不启用,线上使用 'memory'
    ext: ".html", // 模板后缀
});

const app = new koa();
const router = new koaRouter();

app.context.render = co.wrap(render);

let users = [{ username: "张三" }, { username: "李四" }, { username: "王五" }];

router.get("/", (ctx, next) => {
    ctx.body = "home";
});
router.get("/user", (ctx, next) => {
    ctx.body = `<!DOCTYPE html>
<html lang="en">
<head>
    <title>模板文件</title>
</head>
<body>
    <h1>koa swig</h1>
</body>
</html>`;
});
router.get("/list", async (ctx, next) => {
    ctx.body = await ctx.render("1.html", { users });
});

app.use(router.routes());

app.listen(8088);
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    </head>
    <body>
        <h1>koa swig</h1>
        <p>list-{{Math.random()}}</p>
        <ul>
            {% for user in users %}
            <li>{{user.username}}</li>
            {% endfor %}
        </ul>
    </body>
</html>

# mysql2

npm i mysql2
(async () => {
    const mysql = require("mysql2/promise");

    const connection = await mysql.createConnection({
        host: "localhost",
        user: "root",
        database: "test",
    });

    const [rows, fields] = await connection.query("SELECT * FROM todolist");
    console.log(rows);
})();

使用预处理语句

// insert
// const [result] = await connection.query(`INSERT INTO mytable (name, age) VALUES(${name}, ${age})`);
// update
const [result] = await connection.query("UPDATE  `todolist` SET `name` = ? , `age` = ? WHERE `id` = ? ", [
    name,
    age,
    id,
]);
// delete
const [result] = await connection.query(`DELETE FROM todolist WHERE id = ?`, id);

if (result.affectedRows > 0) {
    // 操作成功
} else {
    // 操作失败
}

注意:表名与列名不能使用占位符!

参数标记只能用于数据值应该出现的地方,不能用于 SQL 关键字、标识符等。

Parameter markers can be used only where data values should appear, not for SQL keywords, identifiers, and so forth.

13.5.1 PREPARE Statement (opens new window)

MySQL 中的某些对象,包括数据库、表、索引、列、别名、视图、存储过程、分区、表空间、资源组和其他对象名称,称为标识符。

Certain objects within MySQL, including database, table, index, column, alias, view, stored procedure, partition, tablespace, resource group and other object names are known as identifiers.

9.2 Schema Object Names (opens new window)

# koa-body

npm i koa-body
const Koa = require("koa");
const { koaBody } = require("koa-body");

const app = new Koa();

app.use(koaBody());
app.use((ctx) => {
    ctx.body = `Request Body: ${JSON.stringify(ctx.request.body)}`;
});

app.listen(3000);

# 使用 koa-body 上传文件

文件上传 1

自定义存放文件夹、文件名称与支持多文件上传

// app.js或者自己的路由文件
const fs = require("fs");
const path = require("path");
const koaBody = require("koa-body"); // npm i koa-body
const { format } = require("date-fns"); // npm i date-fns

// POST@/upload
router.post(
    "/upload",
    koaBody({
        multipart: true, // 支持多文件上传
        encoding: "gzip", // 编码格式
        formidable: {
            uploadDir: path.join(__dirname, "/public/upload/"), // 设置文件上传目录
            keepExtensions: true, // 保持文件的后缀
            maxFieldsSize: 10 * 1024 * 1024, // 文件上传大小限制
            onFileBegin: (name, file) => {
                // 无论是多文件还是单文件上传都会重复调用此函数
                // 最终要保存到的文件夹目录
                const dirName = format(new Date(), "yyyyMMddhhmmss");
                const dir = path.join(__dirname, `public/upload/${dirName}`);
                // 检查文件夹是否存在如果不存在则新建文件夹
                if (!fs.existsSync(dir)) {
                    fs.mkdirSync(dir);
                }
                // 文件名称去掉特殊字符但保留原始文件名称
                const fileName = file.name.replaceAll(" ", "_").replace(/[`~!@#$%^&*()|\-=?;:'",<>\{\}\\\/]/gi, "_");
                file.name = fileName;
                // 覆盖文件存放的完整路径(保留原始名称)
                file.path = `${dir}/${fileName}`;
            },
            onError: (error) => {
                app.status = 400;
                log4js.error(error);
                // 这里可以定义自己的返回内容
                app.body = { code: 400, msg: "上传失败", data: {} };
                return;
            },
        },
    }),

    async (ctx) => {
        try {
            // 获取上传文件
            const files = ctx.request.files;
            // 正则 替换掉文件原始路径中不需要的部分
            const reg = new RegExp(".*/upload/", "g");
            for (const fileKey in files) {
                ctx.uploadpaths = ctx.uploadpaths ? ctx.uploadpaths : [];
                ctx.uploadpaths.push({
                    name: files[fileKey].name,
                    url: files[fileKey].path.replace(reg, ""),
                });
            }
            ctx.body = { code: 200, msg: "", data: { uploadpaths: ctx.uploadpaths } };
        } catch (error) {
            ctx.status = 400;
            ctx.body = { code: 400, msg: "上传失败", data: {} };
        }
    }
);

文件上传 2

router.post(
    "/upload",
    koaBody({
        multipart: true, // 支持多文件上传
        encoding: "gzip",
        formidable: {
            maxFieldsSize: 10 * 1024 * 1024, // 文件上传大小限制
            keepExtensions: true, // 保持文件的后缀
        },
    }),
    async (ctx) => {
        let { name, type } = ctx.request.body;
        // 获取上传文件
        const files = ctx.request.files;
        // console.log(files);
        for (let fileKey in files) {
            const file = files[fileKey];
            // 根据文件地址创建文件输入流
            const fileReader = fs.createReadStream(file.filepath);
            // 定义文件存储路径
            let fileDir = path.join(__dirname, "static/img/");
            // 判断路径是否存在
            if (!fs.existsSync(fileDir)) {
                fs.mkdirSync(fileDir);
            }
            let filepath = path.join(fileDir, name);
            if (fs.existsSync(filepath)) {
                let ext = path.extname(name),
                    realname = path.basename(name, ext),
                    newName = realname + "(1)" + ext;
                filepath = path.join(fileDir, newName);
            }
            // 创建文件输出流
            const fileWrite = fs.createWriteStream(filepath);
            // 写入文件数据
            fileReader.pipe(fileWrite);
        }
        ctx.body = {
            code: 0,
            msg: "上传成功",
            url: "/upload" + name,
        };
    }
);