我正在尝试通过Nest / TypeORM构建SAAS产品,我需要通过子域配置/更改数据库连接 .
customer1.domain.com => connect to customer1 database
customer2.domain.com => connect to customer2 database
x.domain.com => connect to x database
我怎样才能做到这一点 ?使用拦截器或请求上下文(或Zone.js)?
我不知道如何开始 . 有人已经这样做了吗?
WIP:我目前在做什么:
-
将所有连接设置添加到ormconfig文件中
-
在所有路由上创建中间件以将子域注入
res.locals
(实例名称)并创建/警告typeorm连接
import { Injectable, NestMiddleware, MiddlewareFunction } from '@nestjs/common';
import { getConnection, createConnection } from "typeorm";
@Injectable()
export class DatabaseMiddleware implements NestMiddleware {
resolve(): MiddlewareFunction {
return async (req, res, next) => {
const instance = req.headers.host.split('.')[0]
res.locals.instance = instance
try {
getConnection(instance)
} catch (error) {
await createConnection(instance)
}
next();
};
}
}
控制器中的
- :从@Response获取实例名称并将其传递给我的服务
@Controller('/catalog/categories')
export class CategoryController {
constructor(private categoryService: CategoryService) {}
@Get()
async getList(@Query() query: SearchCategoryDto, @Response() response): Promise<Category[]> {
return response.send(
await this.categoryService.findAll(response.locals.instance, query)
)
}
- in Service:通过Repository获取给定实例和查询数据库的TypeORM Manager
@Injectable()
export class CategoryService {
// constructor(
// @InjectRepository(Category) private readonly categoryRepository: Repository<Category>
// ) {}
async getRepository(instance: string): Promise<Repository<Category>> {
return (await getManager(instance)).getRepository(Category)
}
async findAll(instance: string, dto: SearchCategoryDto): Promise<Category[]> {
let queryBuilder = (await this.getRepository(instance)).createQueryBuilder('category')
if (dto.name) {
queryBuilder.andWhere("category.name like :name", { name: `%${dto.name}%` })
}
return await queryBuilder.getMany();
}
它似乎工作,但我不确定几乎所有的东西:
-
连接poole(我可以在ConnectionManager中创建多少连接?)
-
将子域传递给response.locals ...不好的做法?
-
可读性/理解/添加大量额外代码......
-
副作用:我害怕在几个子域之间共享连接
-
副作用:表现
处理response.send()Promise await(s)在任何地方传递子域名都不是很高兴...
有没有办法直接将子域名放入我的服务?
有没有办法将正确的子域连接/存储库直接存入我的服务并将其注入我的控制器?
1 回答
我提出了另一个解决方案 .
我创建了一个中间件来获取特定租户的连接:
我把它添加到main.ts:
要访问连接,您可以通过以下方式扩展任何服务:
它仍然是草稿,但使用此解决方案,您可以在运行时为每个租户添加,删除和编辑连接 . 我希望这会对你有所帮助 .