Session
服务器为用户创建的一个会话对象,记录到 cookie 区分用户。
应用场景:注册功能(发送验证码)
后端
# session 插件
pnpm add express-session @types/express-session
# 验证码插件
pnpm add svg-captcha
main.ts
// ...
import * as session from "express-session";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.URI,
});
// app 实例使用 session,通过装饰器 @Session 可以拿到
app.use(
session({
name: "nest.sid", // 会话名称
cookie: { maxAge: 800000 }, // cookie 属性设置
secret: "nest cats", // 加盐
rolling: true, // 每次请求重置 cookie 过期时间
}),
);
await app.listen(3000);
}
bootstrap();
user.controller.ts
import { Body, Controller, Get, Post, Req, Res } from "@nestjs/common";
import { UserService } from "./user.service";
import * as svgCaptcha from "svg-captcha";
@Controller("user")
export class UserController {
constructor(private readonly userService: UserService) {}
@Get("code")
createCaptcha(@Req() req, @Res() res) {
// 用户每次访问该页面时,就会触发 code 更新
const captcha = svgCaptcha.create({
size: 4, // 生成几个验证码
fontSize: 50, // 文字大小
width: 100, // 宽度
height: 32, // 高度
background: "#eaeaea", // 背景颜色
});
req.session.code = captcha.text; // 存储验证码记录到 session
res.type("image/svg+xml");
res.send(captcha.data);
}
@Post("create")
createUser(@Req() req, @Body() body) {
if (req.session.code.toLocaleLowerCase() === body?.validationCode?.toLocaleLowerCase()) {
return {
code: 200,
message: "验证码正确",
};
} else {
return {
code: 400,
message: "验证码错误",
};
}
}
}
前端
技术栈:vite + react + ts + antdesign
App.tsx
import { useState } from "react";
import "./App.css";
import { Button, Checkbox, Form, Input, message } from "antd";
type FieldType = {
username?: string;
password?: string;
remember?: string;
validationCode?: string;
};
function App() {
const [messageApi, contextHolder] = message.useMessage();
const [codeUrl, setCodeUrl] = useState("/api/user/code");
const onFinish = async (values: any) => {
await fetch("/api/user/create", {
method: "POST",
body: JSON.stringify(values),
headers: {
"content-type": "application/json",
},
})
.then((res) => res.json())
.then((res) => {
if (res.code !== 200) {
messageApi.error(res.message);
} else {
messageApi.success(res.message);
}
})
.catch((err) => messageApi.error(err.message));
};
const onFinishFailed = (errorInfo: any) => {
messageApi.error("请正确填写表单");
};
const resetCode = () => {
setCodeUrl(codeUrl + "?" + Math.random());
};
return (
<>
{contextHolder}
<Form
name="basic"
labelCol={{ span: 10 }}
wrapperCol={{ span: 16 }}
style={{
maxWidth: 600,
backgroundColor: "#fff",
padding: 20,
borderRadius: 4,
}}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item<FieldType>
label="Username"
name="username"
rules={[{ required: true, message: "Please input your username!" }]}
>
<Input />
</Form.Item>
<Form.Item<FieldType>
label="Password"
name="password"
rules={[{ required: true, message: "Please input your password!" }]}
>
<Input.Password />
</Form.Item>
<Form.Item<FieldType>
label="ValidationCode"
name="validationCode"
rules={[{ required: true, message: "Please input validation code!" }]}
>
<div>
<Input />
<img onClick={resetCode} src={codeUrl} alt="validationCode" />
</div>
</Form.Item>
<Form.Item<FieldType>
name="remember"
valuePropName="checked"
wrapperCol={{ offset: 8, span: 16 }}
>
<Checkbox>Remember me</Checkbox>
</Form.Item>
<Form.Item wrapperCol={{ offset: 8, span: 16 }}>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</>
);
}
export default App;
Prisma
数据库连接:https://docs.nestjs.com/recipes/prisma#set-the-database-connection
setup
pnpm add prisma
npx prisma init
设置数据库连接(Postgres)
初始化生成的 prisma/schema.prisma:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
.env
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public"
使用 Prisma Migrate 创建数据库表
schema.prisma
model User {
id Int @default(autoincrement()) @id
email String @unique
name String?
posts Post[]
}
model Post {
id Int @default(autoincrement()) @id
title String
content String?
published Boolean? @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}
npx prisma migrate dev --name init
prisma migrate dev 指令会生成 SQL 文件并在数据库中运行。
生成 Prisma Client
Prisma Client 提供 CRUD 接口来操作数据库中的模型字段。
pnpm add @prisma/client
安装时,Prisma 自动地调用了 prisma generate 命令。以后,每次更新 Prisma 模型字段时,都要使用该命令来更新 Prisma Client(node_modules/@prisma/client)。