起步
安装nest
npm i -g @nestjs/cli
新建nest项目
nest new project-name
开发监听启动
npm run start:dev
目录
src
├── app.controller.spec.ts
├── app.controller.ts 控制器
├── app.module.ts 模块
├── app.service.ts 方法服务
└── main.ts 入口
使用
app.controller.ts 控制器
// 引入模块 Get Post对应接口请求类型,Body post参数体 Param get参数体
import { Controller, Get, Post, HttpCode, Body, Param } from '@nestjs/common';
// 方法服务文件
import { AppService } from './app.service';
// 引入自定义返回格式的接口
import { ResData } from './interface/app.interface';
@Controller('api') // 接口前缀,可以自定义
export class AppController {
// 引入AppService后,可以通过this.appService使用AppService内定义的方法
constructor(private readonly appService: AppService) {}
@Post('index') // 接口名称
@HttpCode(200) // 设置状态码,post默认为201
getIndex(@Body() body): ResData {
// return 返回内容,返回string会在页面上打印出来,返回Object,同正常请求接口格式返回
if (body.id) {
let uuid = this.appService.uuid();
}
return { code: 200, data: { uuid }, msg: 'ok' };
}
}
app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
uuid(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
/[xy]/g,
function (c) {
var r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
},
);
}
}
app.interface.ts ts接口
export interface ResData {
code: number;
data: object;
msg: string;
}
数据库
配置env环境,typeorm数据库配置读取.env里的配置
.env
DB_HOST = 127.0.0.1
DB_USERNAME = root
DB_PASSWORD = password
DB_DATABASE = database
ormconfig.js
const { env } = process;
const db = {
type: 'mysql',
host: env.DB_HOST,
port: 3306,
username: env.DB_USERNAME,
password: env.DB_PASSWORD,
database: env.DB_DATABASE,
entities: [
`${env.NODE_ENV === 'development' ? 'dist/' : ''}**/*.entity{.ts,.js}`,
],
synchronize: true,
};
module.exports = db;
安装使用dotenv
npm i dotenv --save
app.module.ts
const dotenv = require('dotenv');
dotenv.config('../.env');
npm script 设置环境变量NODE_ENV
npm i cross-env -D
package.json
"scripts": {
"build": "cross-env NODE_ENV=production nest build",
"start:dev": "cross-env NODE_ENV=development nest start --watch",
}
安装typeorm sql
npm i --save @nestjs/typeorm typeorm mysql2
在app.module.ts引入TypeOrmModule
app.module.ts
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
@Module({
imports: [TypeOrmModule.forRoot()],
})
export class AppModule {
constructor(private readonly connection: Connection) {}
}
存储库
user.entity.ts
mport { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
rimaryGeneratedColumn()
id: number;
@Column()
nickname: string;
@Column()
avatar: string
}
user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class userService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
) {}
/**
* 查找所有用户
* @returns
*/
findAll(): Promise<Store[]> {
return this.usersRepository.find();
}
/**
*
* @param user 用户信息
* @returns
*/
addUser(user): Promise<User> {
return this.usersRepository.save(user);
}
}
user.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { userService } from '../services/store.service';
import { ResData } from '../interface/app.interface';
@Controller('api')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post('user')
async addUser(@Body() body): Promise<ResData> {
let user: any;
user = await this.userService.addUser(body);
return {
code: 200,
data: {
user,
},
msg: 'ok',
};
}
}
user.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule, InjectRepository } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';
import { UserController } from './user.controller';
@Module({
imports: [TypeOrmModule.forFeature([Store])],
providers: [UserService],
controllers: [UserController],
})
export class UsersModule {}
在app.module.ts引入user.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user.module'
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
@Module({
imports: [TypeOrmModule.forRoot(),UserModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
constructor(private readonly connection: Connection) {}
}
拦截器
请求处理成功返回
新建成功拦截器文件
nest g in interceptor/transform
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map((data) => ({
code: 200,
data,
msg: 'ok',
})),
);
}
}
请求处理错误返回
新建错误拦截器文件
nest g f filters/httpExecption
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
} from '@nestjs/common';
import { Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const message = exception.message;
response.status(200).json({
code: status,
message,
});
}
}
错误使用实例
if (false) {
throw new HttpException('错误信息', ‘自定义返回code’);
}
在main.ts中引入拦截器
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { TransformInterceptor } from './interceptor/transform.interceptor';
import { HttpExceptionFilter } from './filters/http-execption.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
app.useGlobalInterceptors(new TransformInterceptor());
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(3000);
}
bootstrap();
认证
passport验证
npm install --save @nestjs/passport passport passport-local @nestjs/jwt passport-jwt
npm install --save-dev @types/passport-local @types/passport-jwt md5
admin.module.ts导出AdminsService,用于auth.service中调用
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Admin } from '../entitys/admin.entity';
import { AdminsService } from '../services/admin.service';
import { AdminController } from '../controller/admin.controller';
@Module({
imports: [TypeOrmModule.forFeature([Admin])],
providers: [AdminsService],
controllers: [AdminController],
exports: [AdminsService]
})
export class AdminsModule {}
admin.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Admin } from '../entitys/admin.entity';
const md5 = require('md5');
@Injectable()
export class AdminsService {
constructor(
@InjectRepository(Admin)
private adminRepository: Repository<Admin>,
) {}
login(params): Promise<Admin> {
let admin = {
username: params.username,
password: md5(params.password),
};
return this.adminRepository.findOne(admin);
}
}
新建auth.service.ts
import { Injectable } from '@nestjs/common';
import { AdminsService } from '../services/admin.service';
@Injectable()
export class AuthService {
constructor(
private readonly adminService: AdminsService,
) {}
async validateUser(username: string, password: string): Promise<any> {
const user = await this.adminService.login({ username, password });
if (user) {
return { ...user };
}
return null;
}
}
新建auth.module.ts
引入AdminsModule assportModule LocalStrategy
import { Module } from '@nestjs/common';
import { AdminsModule } from '../modules/admin.mudule';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
@Module({
imports: [
AdminsModule,
PassportModule,
],
providers: [AuthService, LocalStrategy],
})
export class AuthModule {}
新建local.strategy.ts
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, HttpException } from '@nestjs/common';
import { AuthService } from './auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new HttpException('登录验证失败', 401);
}
return user;
}
}
在app.module.ts引入auth.module
@Module({
imports: [AuthModule],
})
jwt验证
新建jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_SECRET,
});
}
async validate(payload: any) {
return { userId: payload.id };
}
}
auth.module.ts引入JwtModule JwtStrategy
import { Module } from '@nestjs/common';
import { AdminsModule } from '../modules/admin.mudule';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
import { JwtStrategy } from './jwt.strategy';
@Module({
imports: [
AdminsModule,
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: {
// expiresIn: '60s'
},
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],
})
export class AuthModule {}
admin.service.ts引入JwtService
import { Injectable } from '@nestjs/common';
import { AdminsService } from '../services/admin.service';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(
private readonly adminService: AdminsService,
private readonly jwtService: JwtService,
) {}
async validateUser(username: string, password: string): Promise<any> {
const user = await this.adminService.login({ username, password });
if (user) {
return { ...user, access_token: this.jwtService.sign({ id: user.id }) };
}
return null;
}
}
在admin.controller.ts中引入AuthGuard
import {
Controller,
HttpException,
Post,
Body,
UseGuards,
Request,
} from '@nestjs/common';
import { AdminsService } from '../services/admin.service';
import { AuthGuard } from '@nestjs/passport';
@Controller('admin')
export class AdminController {
constructor(private readonly adminService: AdminsService) {}
@UseGuards(AuthGuard('local'))
@Post('login')
async login(@Request() req) {
return req.user;
}
@UseGuards(AuthGuard('jwt'))
@Post('list')
async getList(@Request() req) {
let list = await this.adminService.findAll(req.query);
return { list, page: { total: list.length } };
}
}