AppSync无法查询Post的file字段获取S3文件下载URL问题
嘿,我来帮你搞定这个问题!你现在的情况是已经把文件传到S3了,DynamoDB里也存了file的S3元数据,但就是没法通过查询Post类型拿到这个file字段,对吧?咱们一步步来解决:
首先得确保Post类型里的file字段是可查询的,而且S3Object类型的所有必要属性都正确暴露出来了。比如你的Schema应该类似这样:
type S3Object { bucket: String! key: String! region: String! } type Post { id: ID! # 这里放你的其他Post字段,比如title、content之类的 file: S3Object! # 重点:这个字段必须存在,而且没有被标记为隐藏或不可查询 } type Query { getPost(id: ID!): Post # 其他查询接口,比如listPosts之类的 }
要是你的Schema里Post的file字段被加了@hidden注解,或者根本没在Post类型里定义,那肯定查不到。先把这一步确认好!
如果Schema没问题,那大概率是Resolver没有正确把DynamoDB里的数据映射到Post类型的file字段。毕竟你说DynamoDB里存的是{"s3":{"key":"id.pdf","bucket":"my-bucket","region"...}}这种嵌套结构,Resolver得把这个嵌套的s3节点取出来赋值给Post的file字段。
举个例子,如果你用的是AWS AppSync,响应模板得这么写:
$util.toJson({ "id": $ctx.result.id, # 其他字段的映射,比如"title": $ctx.result.title "file": $ctx.result.file.s3 # 把DB里的file.s3映射到Post的file字段 })
要是你自己写Node.js自定义Resolver,代码大概是这样:
async function getPost(args) { // 从DynamoDB获取Post数据 const post = await dynamoDb.get({ TableName: 'Posts', Key: { id: args.id } }).promise(); // 把嵌套的file.s3提出来作为Post的file字段 return { ...post.Item, file: post.Item.file.s3 }; }
就算你能拿到bucket、key、region,直接给用户这些信息也不太安全,而且用户还要自己拼下载链接。不如在Resolver里直接生成S3预签名URL,这样用户查询Post时就能拿到直接可用的下载链接。
比如用AWS SDK生成预签名URL的Node.js代码:
const AWS = require('aws-sdk'); const s3 = new AWS.S3({ region: process.env.S3_REGION }); async function getPost(args) { const post = await dynamoDb.get({ TableName: 'Posts', Key: { id: args.id } }).promise(); const s3Data = post.Item.file.s3; // 生成有效期1小时的预签名下载URL const downloadUrl = s3.getSignedUrl('getObject', { Bucket: s3Data.bucket, Key: s3Data.key, Expires: 3600 // 单位:秒 }); // 把下载URL加到返回的file对象里 return { ...post.Item, file: { ...s3Data, downloadUrl: downloadUrl } }; }
记得同步更新你的Schema,给S3Object类型加上downloadUrl字段:
type S3Object { bucket: String! key: String! region: String! downloadUrl: String! # 新增这个字段,方便用户直接拿到下载链接 }
要是上面几步都没问题还是查不到file字段,那得检查权限设置:
- 如果是用AWS AppSync,要确保你的查询权限规则允许访问Post类型的file字段;
- 如果是自定义API,要确保用户角色有读取DynamoDB中file字段的权限;
- 要是用了第三步的预签名URL,还要确保Resolver的执行角色有S3的
getObject权限。
内容的提问来源于stack exchange,提问作者Zzz

