我最近搬到了 NestJs。我对定义 mongoose schema 的属性有一些疑问。
如何在模式内定义对象类型:
在express中我定义了这样的属性:
foo:{
type: Object
},
Run Code Online (Sandbox Code Playgroud)
现在在这里我不能使用对象类型。我也确实使用了任何关键字。
我是一名长期学习 NestJS 的 Spring 开发人员。这些相似之处是如此惊人,我很喜欢这让我变得高效。然而,一些文档让我对一件事感到困惑。
我尝试将 Nest“提供者”比作具有默认范围的 Spring beans。例如,我创建 @Injectable 服务类,并将它们视为类似于 Spring @Services。因此,我假设这些服务类需要是线程安全的 - 无状态等。但是,这里的 Nest 文档对我来说有点含糊,有点暗示这可能没有必要(强调我的):
对于来自不同编程语言背景的人来说,可能会意外地发现,在 Nest 中,几乎所有内容都在传入请求之间共享。我们有一个到数据库的连接池、具有全局状态的单例服务等。请记住,Node.js 不遵循请求/响应多线程无状态模型,在该模型中,每个请求都由单独的线程处理。因此,使用单例实例对于我们的应用程序来说是完全安全的。
如果单个请求不在自己的线程中处理,那么 Nest 提供程序可以包含可变状态吗?应用程序需要确保每个传入请求都以“干净的状态”开始 - 例如,使用 NestInterceptor 初始化该状态。但对我来说,该文档显示提供程序是作为单例创建的,因此可以用作类似于数据包装容器的东西,就像 Java 中的 ThreadLocal 一样。
我是否读错了,或者这是 Nest 和 Spring 之间的行为差异?
一段时间以来,我一直在尝试弄清楚如何设置节点调试进程的附件,这些进程在我的环境中从单一存储库设置中的多个正在运行的 Nestjs 应用程序中公开。(用VS代码)
https://github.com/bozvul993/nest-testing-mono-repo-debug
理想情况下,我希望在代码更改时重新启动调试会话[如果可能的话],但更重要的是工作。
我已经为我的示例项目提供了一个存储库。运行/docker文件夹
内的应用程序docker-compose -f dev.yml up
这将显示 monorepo 中的三个应用程序。所有向主机公开其默认节点调试端口的应用程序...
我用来尝试此操作的 vs code 启动配置包括:
"type": "node",
"request": "attach",
"name": "Debug App1",
"address": "0.0.0.0",
"port": 9231,
"localRoot": "${workspaceFolder}/mono-repo",
"remoteRoot": "/app/mono-repo",
"trace": true,
"restart": true,
"sourceMaps": true,
"skipFiles": [
"<node_internals>/**"
]
}
With Web-storm this was easier to achieve somehow..
Run Code Online (Sandbox Code Playgroud) JwtAuthGuard 我在其中验证标头中的令牌:
import { JwtService } from '@nestjs/jwt';
import {
CanActivate,
ExecutionContext,
UnauthorizedException
} from '@nestjs/common';
import { Observable } from 'rxjs';
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
canActivate(
context: ExecutionContext
): boolean | Promise<boolean> | Observable<boolean> {
const req = context.switchToHttp().getRequest();
try {
const authHeader = req.headers.authorization;
const token = authHeader.split(' ')[1];
const user = this.jwtService.verify(token);
req.user = user;
return true;
} catch (error) {
console.log(error);
throw new UnauthorizedException();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的控制器:
import { …Run Code Online (Sandbox Code Playgroud) 在联合嵌套应用程序中,网关收集来自其他服务的所有架构并形成完整的图。问题是,子模式更改后如何重新运行模式集合?
重新启动网关可以解决问题,但这似乎不是一个优雅的解决方案。
我正在尝试构建一个装饰器来“记录”请求信息
export const Tracking = () => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const method = descriptor.value;
descriptor.value = async function(...args: any[]) {
console.log(/** Request info */)
console.log(/** Headers, Body, Method, URL...*/)
return method.call(this, ...args);
}
}
}
Run Code Online (Sandbox Code Playgroud)
并尝试在这样的控制器方法上使用它。
export class Controller {
@Get('/path')
@Tracking()
public async getData(@Headers('user') user: User) {
return this.service.getData(user.id);
}
}
Run Code Online (Sandbox Code Playgroud)
如果这是不可能的,有没有办法将拦截器应用于控制器的某些方法?
或者是否存在用于请求的线程(类似)级上下文?
谢谢!!
我无法异步连接到 mongodb。请让我知道我做错了什么。
蒙戈配置文件:
import { MongooseModuleOptions } from '@nestjs/mongoose';
export default (): { mongoConfig: MongooseModuleOptions } => ({
mongoConfig: {
uri: process.env.DB_URI,
connectionName: 'learn-nest',
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false,
useNewUrlParser: true,
},
});
Run Code Online (Sandbox Code Playgroud)
这是应用程序模块内部编写的代码
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
envFilePath: ['.env'],
isGlobal: true,
cache: true,
}),
MongooseModule.forRootAsync({ …Run Code Online (Sandbox Code Playgroud) 我在 NestJs 中使用 AuthGuard 来验证请求 jwt 令牌。因为我的服务只是验证令牌而不是创建它,所以它不能使用“nbf”验证,以避免创建令牌的服务器的时间晚于我的服务器的情况。
当使用 jsonwebtoken 库使用纯 Node.js 时,可以轻松添加选项来关闭此验证,方法是添加:
jwt.verify(token, cert, {ignoreNotBefore: true})
Run Code Online (Sandbox Code Playgroud)
这也有效。但是,我该如何使用 Nest 来做到这一点呢?
这是我的守卫:
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private reflector: Reflector,
private authService: AuthService) {
super();
}
async canActivate(context: ExecutionContext) {
const isValid = await super.canActivate(context);
return isValid;
}
handleRequest(err, user, info) {
if (err || !user) {
Logger.error(`Unauthorized: ${info && info.message}`);
throw err || new UnauthorizedException();
}
return user;
}
}
Run Code Online (Sandbox Code Playgroud)
在JWT策略中,我尝试在调用PassportStrategy的“super”时添加ignoreNotBefore选项,但这不起作用:
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private …Run Code Online (Sandbox Code Playgroud) 基于这个答案,我尝试在装饰器内实现另一个服务的功能。
这是我的尝试:
export function ClearCache() {
const injectCacheService = Inject(CacheService);
return (target: any, _: string, propertyDescriptor: PropertyDescriptor) => {
injectCacheService(target, 'service'); // this is the same as using constructor(private readonly logger: LoggerService) in a class
//get original method
const originalMethod = propertyDescriptor.value;
//redefine descriptor value within own function block
propertyDescriptor.value = async function (...args: any[]) {
try {
console.log(this);
const service: CacheService = this.service;
service.clearCacheById(args[1]);
return await originalMethod.apply(this, args);
} catch (error) {
console.error(error);
}
};
};
} …Run Code Online (Sandbox Code Playgroud) 我shared在应用程序中使用了具有动态配置的模块。共享模块包含interceptor和service其中包含从共享参数配置的客户端。我通过预定义名称将 注入service到 中interceptor(SharedModule动态导入到 中SecondAppModule)。所以客户名称可以有不同的值。在服务内部,我需要在客户端注入之前知道客户端的名称。现在它是硬编码的:
@Injectable()
export class SumClientService {
constructor(@Inject('MATH_SERVICE') private client: ClientProxy) {
console.log('[SumClientService] - created')
}
sumCalculation(row: number[]): Observable<number> {
return this.client.send<number>({ cmd: 'sum' }, row);
}
}
Run Code Online (Sandbox Code Playgroud)
如果名称仅在构造时已知,是否有任何方法可以按名称从上下文加载服务?
我在列表中检测到两种方法可以将名称作为参数传递到服务中,而不会破坏nest.js. 但我不知道如何访问模块上下文以按指定名称加载服务(想法片段的代码如下)
@Injectable()
export class SumClientService {
constructor(@Inject('service_name') private name: string) {
console.log('[SumClientService] - created')
}
client: (clientName: string) => ClientProxy = (clientName: string): ClientProxy => // TODO load by clientName real …Run Code Online (Sandbox Code Playgroud) nestjs ×10
node.js ×4
typescript ×3
debugging ×1
decorator ×1
graphql ×1
jwt ×1
mongoose ×1
nestjs-jwt ×1
spring ×1