You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 17:40:23