File upload 拒绝&;GraphQL文件上载的错误处理

File upload 拒绝&;GraphQL文件上载的错误处理,file-upload,error-handling,upload,graphql,express-graphql,File Upload,Error Handling,Upload,Graphql,Express Graphql,我有一个带有接受单个文件的解析器的express GraphQL端点。解析程序包括对接收到的文件进行简单的验证 问题是,当验证失败时,无法立即将错误返回到前端,因为抛出错误不会强制中断上载请求 一个过于简化的例子: fileUpload: async (parent, { file, otherdata }) => { const isValid = (some logic here) if(!isValid) throw new ApolloError('

我有一个带有接受单个文件的解析器的express GraphQL端点。解析程序包括对接收到的文件进行简单的验证

问题是,当验证失败时,无法立即将错误返回到前端,因为抛出错误不会强制中断上载请求

一个过于简化的例子:

fileUpload: async (parent, { file, otherdata }) => {
    const isValid = (some logic here)
    if(!isValid)
        throw new ApolloError('upload parameters not valid')

    //No need to get this far,
    //we could have rejected the request already by examining otherdata,
    //or the stream could be already created for max time utilization

    const { createReadStream, filename, mimetype, encoding } = await file;
    const readStream = await createReadStream()
    ...
 }
预期行为:解析程序根据错误策略选项返回通常的{errors:[],data:null}对象或错误本身

实际行为:错误在后端抛出,但请求在前端仍处于挂起状态

我已经尝试了以下方法,但未成功:

  • 仍要初始化readStream并对其调用.destroy()。结果是读取流停止,请求永远挂起
  • 在解析器上下文中包括请求对象(也尝试了响应对象)并对其调用.destroy()。这将结束请求,但会导致前端出现网络错误,因此没有机会进行特定于错误的处理
一些澄清:

  • 显然还有客户端验证,但这并不意味着服务器端验证是不必要的
  • 等待上传完成,然后抛出错误显然是可行的,但从时间和带宽角度看,这并不是一个真正的选项
我知道使用GraphQL上传文件是受支持的边缘功能,但在本例中,我们讨论的是一个相当基本的操作


如果有任何建议,我将不胜感激

事实证明,这是默认的express行为,与GraphQL接口完全无关。 可以找到该解决方案的纯express版本

请求和响应对象应传递到解析器上下文:

const apollo = new ApolloServer({
    typeDefs,
    resolvers,
    context: ({ req, res }) => {
        return {
            req,
            res
        };
    }
});
然后在分解器中,根据示例:

fileUpload: async (parent, { file, otherdata }, {req, res}) => {
    const isValid = (some logic here)
    if(!isValid){
        res.send(403).send("Some message")
        // Throwing ApolloError could also work,
        // in which case response object would not be required, but not tested.
        // throw new ApolloError('upload parameters not valid')
        return req.destroy()
    }
        

    //No need to get this far,
    //we could have rejected the request already by examining otherdata,
    //or the stream could be already created for max time utilization

    const { createReadStream, filename, mimetype, encoding } = await file;
    const readStream = await createReadStream()
    ...
 }

事实证明,这是默认的express行为,与GraphQL接口完全无关。 可以找到该解决方案的纯express版本

请求和响应对象应传递到解析器上下文:

const apollo = new ApolloServer({
    typeDefs,
    resolvers,
    context: ({ req, res }) => {
        return {
            req,
            res
        };
    }
});
然后在分解器中,根据示例:

fileUpload: async (parent, { file, otherdata }, {req, res}) => {
    const isValid = (some logic here)
    if(!isValid){
        res.send(403).send("Some message")
        // Throwing ApolloError could also work,
        // in which case response object would not be required, but not tested.
        // throw new ApolloError('upload parameters not valid')
        return req.destroy()
    }
        

    //No need to get this far,
    //we could have rejected the request already by examining otherdata,
    //or the stream could be already created for max time utilization

    const { createReadStream, filename, mimetype, encoding } = await file;
    const readStream = await createReadStream()
    ...
 }