GraphQL Java中用Schema指令限制Upload标量大小无效求助
问题根源
你定义的@Max指令虽然标注在了Upload标量上,但GraphQL本身不会自动执行标量的指令验证逻辑——这种自定义指令只是个标记,得你自己在服务器端实现对应的验证逻辑才会生效。另外你用@Size限制了上传文件数组的长度,如果这个也没生效,同理也是因为没实现指令的验证逻辑。
解决步骤(以Apollo Server为例)
1. 实现@Max的文件大小验证逻辑
你需要通过SchemaDirectiveVisitor来重写Upload标量的解析过程,添加大小检查:
const { ApolloServer, gql, SchemaDirectiveVisitor } = require('apollo-server'); const { GraphQLUpload } = require('graphql-upload'); // 自定义@Max指令的验证逻辑 class MaxDirective extends SchemaDirectiveVisitor { visitScalar(scalar) { // 保存原解析函数,避免覆盖原有逻辑 const originalParseValue = scalar.parseValue; // 重写解析函数,加入大小验证 scalar.parseValue = async (filePromise) => { // Upload标量返回的是Promise,先获取实际文件对象 const file = await filePromise; // 取指令里配置的最大大小,默认1MB(1048576字节) const maxAllowedSize = this.args.value || 1048576; if (file.size > maxAllowedSize) { throw new Error(this.args.message || `文件不能超过${maxAllowedSize}字节`); } // 执行原解析逻辑(如果有的话) return originalParseValue ? originalParseValue(filePromise) : filePromise; }; } } // 你的Schema定义(可直接指定@Max的大小参数) const typeDefs = gql` directive @Size(min : Int = 0, max : Int = 1, message : String = "graphql.validation.Size.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION directive @Max(value : Int = 1048576, message : String = "graphql.validation.Max.message") on SCALAR scalar Upload @Max(value: 1048576) # 这里可直接设置最大允许大小,比如1MB type Mutation { uploadFile(files: [Upload!] @Size(max : 1)): Boolean } `; // 解析器配置 const resolvers = { Upload: GraphQLUpload, // 使用官方的Upload标量解析器 Mutation: { uploadFile: async (_, { files }) => { // 这里写你的文件处理逻辑 return true; } } }; // 创建服务器并注册指令 const server = new ApolloServer({ typeDefs, resolvers, schemaDirectives: { Max: MaxDirective }, plugins: [require('graphql-upload').GraphQLUploadPlugin()] // 必须启用上传插件 }); server.listen().then(({ url }) => { console.log(`服务器已启动在 ${url}`); });
2. 补全@Size的数组长度验证(如果需要)
如果@Size指令也没生效,同样要实现对应的验证逻辑:
class SizeDirective extends SchemaDirectiveVisitor { visitArgumentDefinition(argument) { const originalResolve = argument.resolve; argument.resolve = async (source, args, context, info) => { const fileList = args[argument.name]; const minLength = this.args.min || 0; const maxLength = this.args.max || 1; if (fileList.length < minLength || fileList.length > maxLength) { throw new Error(this.args.message || `上传文件数量必须在${minLength}到${maxLength}之间`); } return originalResolve ? originalResolve(source, args, context, info) : fileList; }; } } // 然后在server的schemaDirectives里加上:Size: SizeDirective
3. 其他注意事项
- 不同的GraphQL服务器(比如GraphQL Yoga、Hasura)实现自定义指令的方式不一样,得对应调整代码。
- Upload标量的返回值是Promise,必须await后才能拿到
size等文件属性,这一步不能漏。 - 确保已经安装了
graphql-upload依赖,不然Upload标量没法正常工作。
内容的提问来源于stack exchange,提问作者Terence
相关产品推荐
相关产品推荐

