使用 GraphQL 的 Cloudfront 缓存?

Posted

技术标签:

【中文标题】使用 GraphQL 的 Cloudfront 缓存?【英文标题】:Cloudfront cache with GraphQL? 【发布时间】:2017-10-02 05:56:38 【问题描述】:

在我的公司,我们将 graphql 用于生产应用程序,但仅用于私有资源。

目前,我们的公共 API 是带有 Cloudfront 缓存服务的 REST API。我们想将它们转换为 GraphQL API,但问题是:如何使用 GraphQL 正确处理缓存?

我们认为使用 GET graphql 端点,并缓存在查询字符串上,但我们有点害怕请求的 URL 的大小(因为我们支持 IE9+ 并且有时会向学校出售虚拟代理和防火墙)

所以我们想使用 POST graphQL 端点,但是...cloudfront 无法缓存基于其主体的请求

有人有什么想法/最佳实践可以分享吗? 谢谢

【问题讨论】:

【参考方案1】:

我在纸上探索过但尚未实施的一个选项是在请求触发模式下使用 Lambda@Edge 将客户端 POST 转换为 GET,这可能会导致缓存命中。

这样,客户端仍然可以使用 POST 发送 GQL 请求,并且在尝试计算最大 URL 长度时,您正在使用 AWS 内的少量受控服务(这些限制通常非常高)。

仍然会有长度限制,但是一旦您有 16kB+ 的 GQL 请求,可能是时候考虑在服务器上使用预定义查询并仅按名称引用它们的其他建议了。

它确实有一个缺点,即请求触发 Lambda 在每个请求上运行,即使是缓存命中,所以会产生一些成本,尽管 lambda 本身应该非常快速/简单。

【讨论】:

【参考方案2】:

我不确定它是否有一个特定的名称,但我在野外看到了一种模式,其中 graphQL 查询本身托管在具有特定 ID 的后端。 它的灵活性要差得多,因为它需要嵌入预定义的查询。

客户端只需发送参数/参数和所述预定义查询的 ID 以供使用,这将是您的缓存键。类似于 HTTP 缓存如何处理对 /my-profile 的经过身份验证的请求,CloudFront 根据标头中的身份验证令牌提供不同的响应。

客户端如何发送它取决于您对 graphQL 的后端实现。 您可以将其作为白名单标题或查询字符串传递。

所以如果后端定义了一个看起来像这样的查询

(使用伪代码)

const MyQuery = gql`
query HeroNameAndFriends($episode: int) 
  hero(episode: $episode) 
    name
    friends 
      name
    
  

`

那么您的请求将类似于api.app.com/graphQL/MyQuery?episode=3

话虽如此,您是否实际测量过您的查询不适合 GET 请求?如果您需要 CDN 缓存,我会说使用 GET 请求,并对不符合限制的请求使用上述方法。

编辑:似乎它有一个名称:自动持久查询。 https://www.apollographql.com/docs/apollo-server/performance/apq/

保留 POST 请求的另一种方法是在 CloudFront 上使用 Lambda@Edge,并使用 DynamoDB 表来存储缓存,类似于 CloudFlare 工作人员的做法。

async function handleRequest(event) 
    let cache = caches.default
    let response = await cache.match(event.request)
    
    if (!response)
      response = await fetch(event.request)
      if (response.ok) 
        event.waitUntil(cache.put(event.request, response.clone()))
      
    
          
    return response

一些相关的阅读材料

https://aws.amazon.com/blogs/networking-and-content-delivery/lambdaedge-design-best-practices/ https://aws.amazon.com/blogs/networking-and-content-delivery/leveraging-external-data-in-lambdaedge/

【讨论】:

【参考方案3】:

今天最好的两个选择是:

使用专门的缓存解决方案,例如FastQL.io 通过 GET 使用持久查询,其中一些查询保存在您的服务器上并通过 GET 按名称访问

*完全披露:在遇到这些问题但没有好的解决方案后,我启动了 FastQL。

【讨论】:

以上是关于使用 GraphQL 的 Cloudfront 缓存?的主要内容,如果未能解决你的问题,请参考以下文章

Cloudfront 域名无法使用 S3、Cloudfront 和 Route 53 将 HTTP 重定向到 HTTPS

关于使用AWS的CDN-CloudFront的费用计算及说明

为啥需要 Amazon S3 和 Cloudfront?

如何将 CloudFront 和 S3 与备用域一起使用?

使用 Amazon S3 和 Cloudfront 的 CORS

如何获取使用 Cloudfront 上传的 S3 存储桶中的文件?