鲸灵开发-后端开发纪录
前提
项目:低代码产品鲸灵开发
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 使用 @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();