13

我正在上传一个 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 },
  },
});
4

2 回答 2

7

此处的正确方法是使用 AWS AppSync 通过复杂类型执行实际 S3 上传 - 您在此处说明的内容看起来更像是您试图将 base64 编码图像作为字符串保存到我只能假设为的字段中DynamoDB 表条目。但是,要使其正常工作,您需要修改您的突变,以使该file字段不是 a String!,而是 a 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 中的 JSON 字符串file作为模型的字段并将其解析为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-09T02:28:45.740 回答
4

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
}

然后指定一个突变来添加它:

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

于 2017-12-04T03:47:51.793 回答