Graphql
复杂度分析
学习如何在 NestJS GraphQL 中使用复杂度分析来防止恶意查询,包括配置复杂度限制和自定义复杂度计算。
复杂度分析
GraphQL 的强大功能之一是能够任意嵌套查询。虽然这为客户端提供了极大的灵活性,但它也为服务器带来了风险,因为单个查询可能会请求大量嵌套数据。
查询复杂度分析解决了这个问题,通过定义查询的复杂度并设置最大复杂度阈值来防止恶意查询。
安装
首先安装所需的包:
$ npm install graphql-query-complexity
开始使用
一旦安装过程完成,我们可以定义 ComplexityPlugin:
import { GraphQLSchemaHost } from '@nestjs/graphql';
import { Plugin } from '@nestjs/apollo';
import {
ApolloServerPlugin,
GraphQLRequestListener,
} from '@apollo/server';
import { GraphQLError } from 'graphql';
import {
fieldExtensionsEstimator,
getComplexity,
simpleEstimator,
} from 'graphql-query-complexity';
@Plugin()
export class ComplexityPlugin implements ApolloServerPlugin {
constructor(private gqlSchemaHost: GraphQLSchemaHost) {}
requestDidStart(): GraphQLRequestListener<any> {
const { schema } = this.gqlSchemaHost;
return {
didResolveOperation({ request, document }) {
const complexity = getComplexity({
schema,
operationName: request.operationName,
query: document,
variables: request.variables,
estimators: [
fieldExtensionsEstimator(),
simpleEstimator({ maximumComplexity: 1000 }),
],
});
if (complexity >= 20) {
throw new GraphQLError(
`Query is too complex: ${complexity}. Maximum allowed complexity: 20`,
{
extensions: {
code: 'QUERY_TOO_COMPLEX',
},
},
);
}
console.log('Query Complexity:', complexity);
},
};
}
}
为了演示,我们指定了 20 作为最大允许复杂度。在上面的示例中,我们使用了 2 个估算器,simpleEstimator 和 fieldExtensionsEstimator。
简单估算器:简单估算器为每个字段返回固定复杂度
字段扩展估算器:字段扩展估算器从模式中提取复杂度值
现在,将此插件添加到提供者数组中:
@Module({
providers: [ComplexityPlugin],
})
export class CommonModule {}
字段级复杂度
有时,我们需要为特定字段定义不同的复杂度值。我们可以使用 @Complexity() 装饰器来实现这一点。
@Resolver(() => Author)
export class AuthorResolver {
@Query(() => Author)
@Complexity(5)
author() {
return new Author(1, 'John', 'Doe');
}
@ResolveField()
@Complexity(10)
posts(@Parent() author: Author) {
return [];
}
}
@Complexity() 装饰器从 @nestjs/graphql 包导入。
使用 Mercurius
Mercurius 集成了 mercurius-validation 插件,该插件提供查询复杂度分析功能。要启用它,请将 validation 选项传递给 GraphQLModule#forRoot() 方法:
GraphQLModule.forRoot<MercuriusDriverConfig>({
driver: MercuriusDriver,
typePaths: ['./**/*.graphql'],
validation: { complexity: { maximumComplexity: 10 } },
}),
complexity 和 validation 选项都从 mercurius-validation 包导入。