GraphQL 文件上传的拒绝和错误处理
Rejecting & error handling of GraphQL file upload
我有一个 Express GraphQL 端点,它带有接受单个文件的解析器。解析器包括对正在接收的文件的简单验证。
问题是当验证失败时,没有办法立即return把错误传给前端,因为抛出错误不会强制中断上传请求。
一个过度简化的例子:
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()
...
}
预期行为: 解析器 return 是通常的{错误:[],data:null} 对象 - 或错误本身 - 取决于错误策略选项。
实际行为:错误在后端抛出,但请求在前端保持挂起状态。
我已经尝试了以下方法但没有成功:
- 无论如何都初始化 readStream 并在其上调用 .destroy()。结果是读取流停止并且请求永远处于挂起状态。
- 在解析器上下文中包含请求对象(也尝试了响应对象)并在其上调用 .destroy()。这会结束请求,但会导致前端出现网络错误,无法进行特定错误处理。
一些说明:
- 显然也有客户端验证,但这并不意味着不需要服务器端验证。
- 等待上传完成然后抛出错误显然可行,但这不是一个真正的选择,时间和带宽明智。
我知道使用 GraphQL 上传文件是边缘支持的功能,但在这种情况下,我们谈论的是一个相当基本的操作。
如有任何建议,我将不胜感激!
事实证明,这是默认的快速行为,与 GraphQL 接口完全无关。
可以找到解决方案的纯表达版本 .
请求和响应对象应该传递给解析器上下文:
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 端点,它带有接受单个文件的解析器。解析器包括对正在接收的文件的简单验证。
问题是当验证失败时,没有办法立即return把错误传给前端,因为抛出错误不会强制中断上传请求。
一个过度简化的例子:
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()
...
}
预期行为: 解析器 return 是通常的{错误:[],data:null} 对象 - 或错误本身 - 取决于错误策略选项。
实际行为:错误在后端抛出,但请求在前端保持挂起状态。
我已经尝试了以下方法但没有成功:
- 无论如何都初始化 readStream 并在其上调用 .destroy()。结果是读取流停止并且请求永远处于挂起状态。
- 在解析器上下文中包含请求对象(也尝试了响应对象)并在其上调用 .destroy()。这会结束请求,但会导致前端出现网络错误,无法进行特定错误处理。
一些说明:
- 显然也有客户端验证,但这并不意味着不需要服务器端验证。
- 等待上传完成然后抛出错误显然可行,但这不是一个真正的选择,时间和带宽明智。
我知道使用 GraphQL 上传文件是边缘支持的功能,但在这种情况下,我们谈论的是一个相当基本的操作。
如有任何建议,我将不胜感激!
事实证明,这是默认的快速行为,与 GraphQL 接口完全无关。
可以找到解决方案的纯表达版本
请求和响应对象应该传递给解析器上下文:
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()
...
}