问题 缓存Github API调用


我有一个与缓存API调用有关的一般问题,在这个实例中调用Github API。

假设我的应用程序中有一个页面,显示了repo的文件名和README的内容。这意味着我将不得不进行一些API调用以便检索它。

现在,假设我想在两者之间添加类似memcached的东西,所以如果我不需要,我不会一遍又一遍地进行这些调用。

你通常会怎么做?如果我没有在Github上启用webhook,我无法知道缓存是否会过期。我总是可以进行一次调用来获取HEAD的当前sha,如果没有更改,请使用cache。但这是在回购级别,而不是在文件级别。

我可以想象我可以使用object-sha来做类似的事情,但是如果我需要调用API来获取它们,它就会失去缓存的目的。

你会怎么做?我知道像prose.io这样的服务现在没有缓存,但如果它应该,那么这种方法是什么?

谢谢


7711
2018-02-15 00:42


起源



答案:


只是使用HTTP缓存对你的用例来说足够好吗? HTTP缓存的目的不仅仅是提供一种在没有新响应的情况下不发出请求的方式,而是 - 它还使您能够快速验证缓存中已有的响应是否有效(没有服务器发送完整的响应)如果它是新鲜的再次响应)。

看看GitHub API响应,我可以看到GitHub正确设置了相关的HTTP头(ETag,Last-modified,Cache-control)。

所以,你只需要做一个GET,例如对于:

GET https://api.github.com/users/izuzak/repos

这会返回:

200 OK
...
ETag:"df739f00c5053d12ef3c625ad6b0fd08"
Last-Modified:Thu, 14 Feb 2013 22:31:14 GMT
...

下次 - 您为同一资源执行GET,但也提供相关的HTTP缓存头,以便它实际上是一个条件GET:

GET https://api.github.com/users/izuzak/repos
...
If-Modified-Since:Thu, 14 Feb 2013 22:31:14 GMT
If-None-Match:"df739f00c5053d12ef3c625ad6b0fd08"
...

并且看到 - 服务器返回304 Not modified响应,您的HTTP客户端将从其缓存中提取响应:

304 Not Modified

因此,GitHub API可以正确进行HTTP缓存,您应该使用它。当然,您还必须使用支持HTTP缓存的HTTP客户端。最好的办法是,如果你得到一个304 Not modified响应--GitHub不会减少你剩余的API调用配额。看到: http://developer.github.com/v3/#conditional-requests

GitHub API也设置了 Cache-Control: private, max-age=60 标题,所以你有60秒的新鲜度 - 这意味着相隔不到60秒的相同资源的请求甚至不会被提供给服务器。

关于对资源使用单个条件GET请求的理由,如果repo中的任何内容发生变化(例如,显示HEAD sha的资源)肯定会发生变化,这听起来是合理的 - 因为如果该资源没有改变,那么你就不要因为它们没有确定地改变,所以必须检查各个文件。


15
2018-02-15 08:40



谢谢伊万。这很棒。使用HTTP缓存还意味着我不需要自己的中间层API路由来缓存memcached中的内容。这样我就可以直接从客户端通过CORS(如果需要可以使用本地存储)。 - Ronze
是不是所有来自github的端点都可能返回 Last-Modified 头?例如,对里程碑端点的调用不返回任何内容 Last-Modified 标题:curl -i api.github.com/repos/p1nox/repos/milestones  但确实会回来 ETag,那么缓存这种资源的唯一方法就是使用组合令牌-etag吧? - p1nox
@ p1nox是的,这是可能的。如果你读到这个 developer.github.com/v3/#conditional-requests,你会注意到这一部分:“大多数响应返回一个ETag标题。许多响应也返回一个Last-Modified标题。”请注意,它表示“最多”和“很多”,而不是“全部”。 - Ivan Zuzak
是的,我看到了,但是有点暧昧,我希望我读完后的假设不是真的:P。谢谢@IvanZuzak。 - p1nox


答案:


只是使用HTTP缓存对你的用例来说足够好吗? HTTP缓存的目的不仅仅是提供一种在没有新响应的情况下不发出请求的方式,而是 - 它还使您能够快速验证缓存中已有的响应是否有效(没有服务器发送完整的响应)如果它是新鲜的再次响应)。

看看GitHub API响应,我可以看到GitHub正确设置了相关的HTTP头(ETag,Last-modified,Cache-control)。

所以,你只需要做一个GET,例如对于:

GET https://api.github.com/users/izuzak/repos

这会返回:

200 OK
...
ETag:"df739f00c5053d12ef3c625ad6b0fd08"
Last-Modified:Thu, 14 Feb 2013 22:31:14 GMT
...

下次 - 您为同一资源执行GET,但也提供相关的HTTP缓存头,以便它实际上是一个条件GET:

GET https://api.github.com/users/izuzak/repos
...
If-Modified-Since:Thu, 14 Feb 2013 22:31:14 GMT
If-None-Match:"df739f00c5053d12ef3c625ad6b0fd08"
...

并且看到 - 服务器返回304 Not modified响应,您的HTTP客户端将从其缓存中提取响应:

304 Not Modified

因此,GitHub API可以正确进行HTTP缓存,您应该使用它。当然,您还必须使用支持HTTP缓存的HTTP客户端。最好的办法是,如果你得到一个304 Not modified响应--GitHub不会减少你剩余的API调用配额。看到: http://developer.github.com/v3/#conditional-requests

GitHub API也设置了 Cache-Control: private, max-age=60 标题,所以你有60秒的新鲜度 - 这意味着相隔不到60秒的相同资源的请求甚至不会被提供给服务器。

关于对资源使用单个条件GET请求的理由,如果repo中的任何内容发生变化(例如,显示HEAD sha的资源)肯定会发生变化,这听起来是合理的 - 因为如果该资源没有改变,那么你就不要因为它们没有确定地改变,所以必须检查各个文件。


15
2018-02-15 08:40



谢谢伊万。这很棒。使用HTTP缓存还意味着我不需要自己的中间层API路由来缓存memcached中的内容。这样我就可以直接从客户端通过CORS(如果需要可以使用本地存储)。 - Ronze
是不是所有来自github的端点都可能返回 Last-Modified 头?例如,对里程碑端点的调用不返回任何内容 Last-Modified 标题:curl -i api.github.com/repos/p1nox/repos/milestones  但确实会回来 ETag,那么缓存这种资源的唯一方法就是使用组合令牌-etag吧? - p1nox
@ p1nox是的,这是可能的。如果你读到这个 developer.github.com/v3/#conditional-requests,你会注意到这一部分:“大多数响应返回一个ETag标题。许多响应也返回一个Last-Modified标题。”请注意,它表示“最多”和“很多”,而不是“全部”。 - Ivan Zuzak
是的,我看到了,但是有点暧昧,我希望我读完后的假设不是真的:P。谢谢@IvanZuzak。 - p1nox