【问题标题】:How to upload an image to AWS S3 using GraphQL?如何使用 GraphQL 将图像上传到 AWS S3?
【发布时间】:2018-01-19 09:38:23
【问题描述】:

我正在上传 base64 字符串,但 GraphQL 挂起。如果我将字符串切成少于 50,000 个字符,它就可以工作。在 50,000 个字符之后,graphQL 永远不会进入 resolve 函数,但不会给出错误。在较小的字符串上,它工作得很好。

const file = e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
  const imageArray = reader.result;
  this.context.fetch('/graphql', {
    body: JSON.stringify({
      query: `mutation s3Upload($img: String!) {
        s3Upload(file: $img) {
          logo,
        }
      }`,
      variables: {
        img: imageArray,
      },
    }),
  }).then(response => response.json())
  .then(({ data }) => {
    console.log(data);
  });
}

const s3Upload = {
    type: S3Type,
    args: {
      file: { type: new NonNull(StringType) },
    },
    resolve: (root, args, { user }) => upload(root, args, user),
};

const S3Type = new ObjectType({
  name: 'S3',
  fields: {
    logo: { type: StringType },
  },
});

【问题讨论】:

    标签: javascript reactjs amazon-s3 graphql aws-appsync


    【解决方案1】:

    AWS AppSync (https://aws.amazon.com/appsync/) 为其提供了称为“复杂对象”的功能,您可以在其中为 S3 对象和输入提供类型:

    type S3Object {
        bucket: String!
        key: String!
        region: String!
    }
    
    input S3ObjectInput {
        bucket: String!
        key: String!
        region: String!
        localUri: String
        mimeType: String
    }
    

    然后您可以执行以下操作来将此对象定义为另一种类型的一部分:

    type UserProfile {
        id: ID!
        name: String
        file: S3Object
    }
    

    然后指定一个mutation来添加它:

    type Mutation {
        addUser(id: ID! name: String file: S3ObjectInput): UserProfile!
    }
    

    您的客户端操作需要指定适当的存储桶、密钥(带有文件扩展名)、区域等。

    更多:https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-react.html#complex-objects

    【讨论】:

    • 谢谢@Richard。您引用的教程没有显示如何更改 NewPostMutation.js。我试图按照本教程进行操作,但到目前为止还没有运气在 s3 上上传文件:-(
    【解决方案2】:

    此处的正确方法是使用 AWS AppSync 通过复杂类型执行实际 S3 上传 - 您在此处说明的内容看起来更像是您试图将 base64 编码图像作为字符串保存到我只能假设的字段中成为 DynamoDB 表条目。但是,要使其正常工作,您需要修改您的突变,使file 字段不是String!,而是S3ObjectInput

    在“正常工作”(TM) 之前,您需要确保在引擎盖下有一些活动部件就位。首先,您需要确保为 GraphQL 架构中定义的 S3 对象提供适当的输入和类型

    enum Visibility {
        public
        private
    }
    
    input S3ObjectInput {
        bucket: String!
        region: String!
        localUri: String
        visibility: Visibility
        key: String
        mimeType: String
    }
    
    type S3Object {
        bucket: String!
        region: String!
        key: String!
    }
    

    S3ObjectInput 类型当然是在上传新文件时使用的——通过创建或更新嵌入了所述 S3 对象元数据的模型。它可以通过以下方式在突变的请求解析器中处理:

    {
        "version": "2017-02-28",
        "operation": "PutItem",
        "key": {
            "id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id),
        },
    
        #set( $attribs = $util.dynamodb.toMapValues($ctx.args.input) )
        #set( $file = $ctx.args.input.file )
        #set( $attribs.file = $util.dynamodb.toS3Object($file.key, $file.bucket, $file.region, $file.version) )
    
        "attributeValues": $util.toJson($attribs)
    }
    

    这是假设 S3 文件对象是附加到 DynamoDB 数据源的模型的子字段。请注意,对$utils.dynamodb.toS3Object() 的调用设置了复杂的S3 对象file,这是一个类型为S3ObjectInput 的模型字段。以这种方式设置请求解析器会处理将文件上传到 S3(当所有凭据都设置正确时 - 我们稍后会谈到),但它没有解决如何获取 S3Object背部。这就是需要附加到本地数据源的字段级解析器的地方。本质上,您需要在 AppSync 中创建一个本地数据源,并使用以下请求和响应解析器将其连接到架构中模型的 file 字段:

    ## Request Resolver ##
    {
        "version": "2017-02-28",
        "payload": {}
    }
    
    ## Response Resolver ##
    $util.toJson($util.dynamodb.fromS3ObjectJson($context.source.file))
    

    这个解析器只是告诉 AppSync 我们想要获取存储在 DynamoDB 中模型的 file 字段的 JSON 字符串,并将其解析为 S3Object - 这样,当您查询模型时,而不是返回存储在 file 字段中的字符串,您将获得一个包含 bucketregionkey 属性的对象,您可以使用这些属性构建 URL 以访问 S3 对象(直接通过S3 或使用 CDN - 这真的取决于您的配置)。

    不过,请确保您已为复杂对象设置了凭据(告诉过您我会回到这个问题上)。我将使用一个 React 示例来说明这一点 - 在定义您的 AppSync 参数(端点、身份验证等)时,需要定义一个名为 complexObjectCredentials 的附加属性来告诉客户端使用什么 AWS 凭证来处理S3 上传,例如:

    const client = new AWSAppSyncClient({
        url: AppSync.graphqlEndpoint,
        region: AppSync.region,
        auth: {
            type: AUTH_TYPE.AWS_IAM,
            credentials: () => Auth.currentCredentials()
        },
        complexObjectsCredentials: () => Auth.currentCredentials(),
    });
    

    假设所有这些东西都准备好了,通过 AppSync 的 S3 上传和下载应该可以工作。

    【讨论】:

      猜你喜欢
      • 2018-05-12
      • 1970-01-01
      • 2020-12-23
      • 2018-03-02
      • 1970-01-01
      • 2020-08-07
      • 1970-01-01
      • 2015-04-18
      • 1970-01-01
      相关资源
      最近更新 更多