Я строю API-интерфейс GraphQL с использованием среды Nest и пытаюсь внедрить стороннее экспресс-промежуточное ПО ( express-rate-limit и express-slow-down ) внекоторые запросы и мутации.
Проблема в том, что все мутации graphql и запросы используют одну и ту же конечную точку, поэтому я не могу точно сказать, к какому запросу или мутациям будет применяться промежуточное программное обеспечение, потому что вы можете сделать это только с помощью routeпуть (который одинаков в API).
import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common'
import * as rateLimit from 'express-rate-limit'
import * as RedisStore from 'rate-limit-redis'
import { RedisClient } from 'redis'
@Module({
providers: [],
exports: [],
})
export default class SecurityModule implements NestModule
{
constructor(protected readonly redisClient: RedisClient)
{
}
configure(consumer: MiddlewareConsumer)
{
consumer.apply(
new rateLimit({
max: 300,
windowMs: 15 * 60 * 1000,
store: new RedisStore({ client: this.redisClient }),
})).forRoutes({ path: '/graphql', method: RequestMethod.ALL }) // this would apply the middleware to all queries and mutations
}
}
Поэтому я попытался использовать для этой цели как охранников, так и перехватчиков, но с треском провалился.
Это сбой по очевидной причине.Error: Can't set headers after they are sent
выбрасывается.
/* !!! My Interceptor would like quite identical */
import { ExecutionContext, Injectable, CanActivate } from '@nestjs/common'
import * as speedLimit from 'express-slow-down'
import { Request, Response } from 'express'
@Injectable()
export default class SpeedLimitGuard implements CanActivate
{
constructor(
protected readonly options: speedLimit.Options,
) {
}
async canActivate(context: ExecutionContext): Promise<boolean> {
const { req, res }: { req: Request, res: Response } = context.getArgs()[2]
speedLimit({ ...this.options })(req, res, req.next)
return true
}
}
import { NestInterceptor, ExecutionContext, Injectable, INestApplication, INestExpressApplication } from '@nestjs/common'
import { Observable } from 'rxjs'
import * as speedLimit from 'express-slow-down'
// import { Request, Response } from 'express'
import { ApplicationReferenceHost } from '@nestjs/core'
import { RedisClient } from 'redis'
import * as RedisStore from 'rate-limit-redis'
@Injectable()
export default class SpeedLimitInterceptor implements NestInterceptor
{
constructor(private readonly appRefHost: ApplicationReferenceHost,
private readonly redisClient: RedisClient, )
{}
intercept<T>(context: ExecutionContext, call$: Observable<T>): Observable<T>
{
// const { req: request, res: response }: { req: Request, res: Response } = context.getArgs()[2]
const httpServer = this.appRefHost.applicationRef
const app: INestApplication & INestExpressApplication = httpServer.getInstance()
app.use(speedLimit({
delayAfter: 1,
store: new RedisStore({
prefix: 'test_',
client: this.redisClient,
}),
}))
app.use((req, res, next) => {
console.log('is middleware triggered', { req, res })
next()
})
return call$
}
}
Есть ли способ явно применить промежуточное промежуточное программное обеспечение сторонних производителей для мутации / запроса GraphQL?