跳到主要内容

鲸灵开发-后端开发纪录

前提

项目:低代码产品鲸灵开发

Github地址:xiaojunnanya/whale-dev: 低代码产品后端 (github.com)

技术栈nestjs

nest版本:@10.1.8

node版本:@16.16.0

开发纪录

配置@路径

// tsconfig.json
{
"compilerOptions": {
...
"baseUrl": "./",
"paths":{
"@/*":["src/*"]
}
}
}

捕获异常

捕获所有http返回的异常,返回自己想要的格式

// src\common\expection\http-exception.filter.ts

import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response } from 'express';

// 对于HttpException的异常捕获
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;

let errorMessage = exception instanceof HttpException ? exception.getResponse() : 'Internal server error';
errorMessage = typeof errorMessage === 'string' ? errorMessage : (errorMessage as { message: string}).message;

const errorResponse = {
statusCode: status,
timestamp: new Date().toString(),
path: request.url,
message: 'error',
data: errorMessage
};

response.status(status).json(errorResponse);
}
}
// main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpException, HttpStatus, ValidationPipe } from '@nestjs/common';
import { AllExceptionsFilter } from '@/common/expection/http-exception.filter';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

// 添加
app.useGlobalFilters(new AllExceptionsFilter());

await app.listen(3001);
}
bootstrap();

捕获class-validator抛出的异常

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpException, HttpStatus, ValidationPipe } from '@nestjs/common';
import { AllExceptionsFilter } from '@/common/expection/http-exception.filter';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

// 捕获class-validator抛出的异常
app.useGlobalPipes(new ValidationPipe({
exceptionFactory: (validationErrors = []) => {

const formattedErrors = validationErrors.reduce((acc, error) => {
acc[error.property] = Object.values(error.constraints)
return acc;
}, {});

return new HttpException({
statusCode: HttpStatus.BAD_REQUEST,
message: formattedErrors,
}, HttpStatus.BAD_REQUEST);
},
}));

app.useGlobalFilters(new AllExceptionsFilter());

await app.listen(3001);
}
bootstrap();

prisma时间差

Prisma 避坑指南

Prisma 使用 @createAt@updateAt 时差问题怎么解决?(这里是mysql,其它应该同理)

prisma 使用了 @createAt@updateAt 在其引擎内部处理时,同一处理成了 UTC 时间格式,也就是比北京时间慢 8个小时。(mysql 、linux 时间均正常的情况下)

可能引擎是国外开发的吧,想自动创建时间,以及修改自动更新时间的话,上面两种不能采取。使用如下方式取代:

model Dept {
id Int @id @default(autoincrement())
email String
code String
createAt DateTime @default(now())
updateAt DateTime @updatedAt @map("created_time")
}

---- 使用@default(now())和@updatedAt是不行的 ---

model email_code{
id Int @id @default(autoincrement())
email String
code String
createAt DateTime @default(dbgenerated("NOW()")) @db.DateTime
updateAt DateTime @default(dbgenerated("NOW() ON UPDATE NOW()")) @db.Timestamp(0) @map("created_time")
}

设置token

// login.module.ts

import { Module } from '@nestjs/common';
import { LoginService } from './login.service';
import { LoginController } from './login.controller';
import { JwtModule } from '@nestjs/jwt';
import { TOKEN } from '@/config';

@Module({
imports:[
JwtModule.register({
global: true,
secret: TOKEN.secret,
signOptions: { expiresIn: TOKEN.expiresIn },
})
],
controllers: [LoginController],
providers: [LoginService],
})
export class LoginModule {}
// login.service.ts

import { JwtService } from '@nestjs/jwt'

export class LoginService {
constructor(
private jwtService: JwtService,
) {}
// 参数是我们设置的东西
const token = this.jwtService.sign({ userId, email })
}

验证token

// auth.guard.ts

import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { TOKEN } from '@/config';

// 通过注入的方式来设置接口是否要token:@UseGuards(AuthGuard)

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const req = context.switchToHttp().getRequest();
const { token } = req.headers
if (!token) {
throw new UnauthorizedException()
}
try {
const payload = await this.jwtService.verifyAsync(
token,
{
secret: TOKEN.secret
}
);

req['userId'] = payload?.userId;
req['email'] = payload?.email;
} catch {
throw new UnauthorizedException();
}
return true;
}

// private extractTokenFromHeader(req: Request): string | undefined {
// const [type, token] = req.headers.authorization?.split(' ') ?? [];
// return type === 'Bearer' ? token : undefined;
// }
}

访问静态文件

import { NestExpressApplication } from '@nestjs/platform-express';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';

async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);

// 静态资源的展示(第一个参数是本地路径,第二个参数是url的前缀)
app.useStaticAssets('src/assets/images/avatar', {prefix: '/avatar'})

await app.listen(3001);
}
bootstrap();