在阅读本指南前,我们假设您已经阅读过Nest.js官方文档并能够独立本机启动MySQL与Redis的能力。
开发阶段通常不会使用docker进行启动,更多的是本地启动。首先我们要配置环境变量文件, 也就是.env文件
# 数据库IP (一般是本地)
DATABASE_HOST = 'localhost'
# 数据库端口
DATABASE_PORT = 3306
# 数据库用户名
DATABASE_USERNAME = 'root'
# 数据库密码
DATABASE_PASSWORD = 'root'
# 数据库名 (请确保该库存在)
DATABASE_NAME = 'ospp-nest'
# 请阅读: https://www.typeorm.org/migrations
# 线上环境请关闭
DATABASE_SYNCHRONIZE = 'true'
DATABASE_AUTOLOADENTITIES = 'true'
# jwt secret
AUTH_SECRET = 'secret'
REDIS_SECONDS = 7200
# redis ip
REDIS_HOST = 'localhost'
# redis 端口
REDIS_PORT = 6379
# token过期时间
EXPIRES_IN = '2h'
# 分页默认起始页 (一般可以不修改)
PAGINATION_PAGE = 1
# 分页默认大小
PAGINATION_LIMIT = 10- 后端项目已被初始化
-
.env文件中DATABASE_HOST是开发环境 -
.env文件中DATABASE_NAME为开发库 -
.env文件中DATABASE_NAME存在 -
.env文件中DATABASE_SYNCHRONIZE为true -
.env文件中REDIS_HOST是开发环境 - MySQL服务可以正常访问
- Redis服务可以正常访问
-
dist目录被删除 (可选,如果你不需要测试初始化数据的话)
配置好文件后您可以运行npm run start:dev来运行后端服务。当出现下述字样时,表示后端启动成功。
LOG [NestApplication] Nest application successfully started +11ms
Application is running on: http://[::1]:3000
TinyPro 提供了一个 RejectGuard 的 Guard. 如果你需要关闭演示模式, 请在 nestJS/src/app.module.ts 中移除 L66~L69. 最终代码应当如下
@Module({
...
providers: [
{
provide: APP_GUARD,
useClass: AuthGuard,
},
- {
- provide: APP_GUARD,
- useClass: RejectRequestGuard,
- },
{
provide: APP_GUARD,
useClass: PermissionGuard,
},
],
})
export class AppModule implements OnModuleInit {有些时候我们需要自动初始化一些数据(比如前端的默认国际化字段). 这些逻辑均需写在App.module.ts中AppModule类中的onModuleInit函数中。
这里的国际化指的是报错信息的国际化
后端采用的是nestjs-i18n依赖库。国际化词条放在i18n/<lang>/xxx.json下
i18n
enUS
exception.json
validation.json
zhCN
exception.json
validation.json
目前仅支持enUS与zhCN两种语言,且fallback为enUS.
后端服务遵循Restful规范,可以直接抛出错误使用HttpStatusCode来代替错误代码。如果需要使用国际化词条,请确保该词条已经存在于enUS|zhCN/exception.json文件内。假设有一个服务PolicyService需要抛出一个409错误。
- 添加国际化词条
- 在服务中注入
I18nService - 使用该词条
// zhCN/exception.json
{
// 前面不做修改
"policy":{
"exists": "Policy已存在"
}
}import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { I18nTranslations } from '../.generate/i18n.generated';
import { I18nContext, I18nService } from 'nestjs-i18n';
@Injectable()
export class PolicyService {
constructor(
private readonly i18n: I18nService<I18nTranslations>
) {}
createPolicy(){
const exists = ...;
if (exists){
throw new HttpException(
this.i18n.translate('exception.policy.exists', {
lang: I18nContext.current().lang,
}),
HttpStatus.CONFLICT // 409
)
}
//....
}
}凡是没有被Public修饰器修饰的接口,均会被auth/auth.guard.ts进行校验,如果token不存在、token过期、token不合法,均不允许访问。
如果一个接口没有被Permission修饰器进行修饰,那么这个接口是允许所有已经登录的用户访问。如果一个接口被Permission修饰器进行修饰,那么该接口仅允许拥有该权限的用户访问,其余用户会返回403错误代码
默认admin用户存在超级权限(*), 拥有该权限且已经登陆的用户可以访问任何接口。
例如
@Controller('/policy')
export class PolicyController {
@Get('/list')
async getPolicy(){}
}上述代码中GET /policy/list是一个不公开,不受保护的接口。我们可以使用Permission修饰器对他进行权限认证,当且仅当用户角色存在policy::get::list权限时才放行
@Controller('/policy')
export class PolicyController {
@Get('/list')
@Permission('policy::get::list')
async getPolicy(){}
}这样一来GET /policy/list就只允许拥有policy::get::list权限的角色访问,其余角色访问则会返回一个403错误
但有些时候我们需要一个接口允许未登陆的用户访问。例如我们在登陆的时候经常需要获取免责声明,那么我们就可以写一个GET /policy接口,用于获取一个免责声明的法律条文。
所以我们可以添加如下
@Controller('/policy')
export class PolicyController {
@Get('/list')
@Permission('policy::get::list')
async getPolicies(){}
@Get('/')
@Public()
async getPolicy(){}
}这样一来GET /policy/list接口只允许登录且拥有policy::get::list权限的角色访问。GET /policy接口则允许未登陆的所有角色进行访问。
如果未来的某一天,我们需要让/policy/*都允许未登录的用户访问,那么我们可以这么写
@Public()
@Controller('/policy')
export class PolicyController {
@Get('/list')
async getPolicies(){}
@Get('/')
async getPolicy(){}
}这样一来,所有的policy接口都可以被未登录的用户访问了
加官方小助手微信 opentiny-official,加入技术交流群
请阅读SWC
为了避免重复初始化,系统会在第一次初始化的时候在dist目录下新建app/lock文件,如果您需要再次初始化,那么请您删除dist/app或者直接删除dist文件夹
docker-compose.yaml实际上配置了depends_on字段,但mysql镜像并没有提供对应的健康检查。如果服务挂掉,可以等待mysql启动成功后手动重启后端服务