简介ð
缓存是网络开发中用于提高应用程序性能的重要技术。它涉及将经常访问的数据存储在临时存储区域(例如内存)中,以减少从其源获取数据所需的时间。
有不同类型的缓存,包括内存中心,数据库缓存和基于文件的缓存。每种类型都有其优点和缺点,并且选择正确的一种取决于特定用例和应用程序的要求。
内存中的缓存是可用的最简单,最快的缓存方法之一,使其成为许多应用程序的流行选择。它涉及将数据存储在服务器的内存中,使应用程序可以快速访问应用程序,而无需任何外部依赖关系。
在这篇博客文章中,我们将重点介绍Golang的内存中缓存,并以简单的API为例演示其实现。到本博客结束时,您将对内存中的缓存作品有深入的了解。
先决条件
要继续进行教程,首先您需要安装Golang和光纤。
安装:
入门ð
让我们通过使用以下命令创建主要项目目录Go-Cache-API
开始。
(ð¥请小心,有时我通过在代码中发表评论来完成解释)
mkdir Go-Cache-API //Creates a 'Go-Cache-API' directory
cd Go-Cache-API //Change directory to 'Go-Cache-API'
现在初始化一个mod文件。 (如果您发布模块,则必须是通过Go Tools下载模块的路径。这将是您的代码存储库。)
go mod init github.com/<username>/Go-Cache-API //<username> is your github username
安装光纤框架运行以下命令:
go get -u github.com/gofiber/fiber/v2
用于实现内存中的缓存我们将要使用go-cache
,以安装它运行以下命令:
go get github.com/patrickmn/go-cache
go-cache
是一个内存密钥:值存储/高速缓存类似于适合在单台计算机上运行的应用程序的memcached。
现在,让我们制作要定义路线的main.go
。
package main
import (
"time"
"github.com/gofiber/fiber/v2"
"github.com/Siddheshk02/Go-Cache-API/middleware"
"github.com/Siddheshk02/Go-Cache-API/routes"
"github.com/patrickmn/go-cache"
)
func main() {
app := fiber.New() // Creating a new instance of Fiber.
//cache := cache.New(10*time.Minute, 20*time.Minute) // setting default expiration time and clearance time.
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World 👋!")
})
//app.Get("/posts/:id", middleware.CacheMiddleware(cache), routes.GetPosts) //commenting this route just to test the "/" endpoint.
app.Listen(":8080")
}
在main.go
文件中,第一步是使用fiber.New()
方法初始化新的光纤应用。这将创建一个将处理HTTP请求和响应的光纤框架的新实例。
我们将使用https://jsonplaceholder.typicode.com/来获取示例数据。我们将从 /帖子端点获取数据。 Jsonplaceholder为您可以尝试任何其他API端点提供虚假数据。
cache.New()
函数采用两个参数:
- 第一个参数是缓存条目在自动驱逐之前应延续的时间。在这种情况下,设置为10分钟。
- 第二个参数是缓存条目可以在自动驱逐之前保持空闲(无访问)的时间。在这种情况下,设置为20分钟。
运行go run main.go
命令后,终端将看起来像这样,
您现在可以输入所有代码行。
您可以看到中间软件功能已添加到/posts
路由中。当向该端点提出请求时,服务器将首先使用缓存参数执行CacheMiddleware
函数。此中间软件功能负责检查请求的数据是否已被缓存并从缓存中返回,而不是进行新的API调用。如果缓存中不存在数据,则中间件功能将将请求传递给中间件链中的下一个功能,即routes.GetPosts
。
routes.GetPosts
是一个函数,当请求达到这一点时将执行。此功能将通过向https://jsonplaceholder.typicode.com/posts/:id
上的外部API提出获取帖子数据来处理请求。 URL的:id
部分是占位符,将被请求的帖子的实际ID替换。
让我们为此定义CacheMiddleware()
函数,在主目录中制作一个文件夹中间件。在此制作文件cache.go
。
package middleware
import (
"encoding/json"
"time"
"github.com/gofiber/fiber/v2"
"github.com/patrickmn/go-cache"
)
type Post struct {
UserID int `json:"userId"`
ID int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func CacheMiddleware(cache *cache.Cache) fiber.Handler {
return func(c *fiber.Ctx) error {
if c.Method() != "GET" {
// Only cache GET requests
return c.Next()
}
cacheKey := c.Path() + "?" + c.Params("id") // Generate a cache key from the request path and query parameters
// Check if the response is already in the cache
if cached, found := cache.Get(cacheKey); found {
return c.JSON(cached)
}
err := c.Next()
if err != nil {
return err
}
var data Post
cacheKey := c.Path() + "?" + c.Params("id")
body := c.Response().Body()
err = json.Unmarshal(body, &data)
if err != nil {
return c.JSON(fiber.Map{"error": err.Error()})
}
// Cache the response for 10 minutes
cache.Set(cacheKey, data, 10*time.Minute)
return nil
}
}
中间件函数CacheMiddleware
将指针作为参数作为参数并返回fiber.Handler
函数。
中间件功能首先检查请求的HTTP方法是否为GET
。如果不是GET
请求,它只需将请求传递给下一个中间件函数。
如果它是GET
请求,它通过连接请求路径和查询参数来生成缓存键。然后,它通过使用cache.Cache
对象的GET方法来检查该缓存键的响应是否已经存在。如果缓存中存在响应,则使用fiber.Ctx
对象的JSON方法返回缓存的响应。
如果缓存中不存在响应,则使用fiber.Ctx
对象的下一个方法调用下一个中间件函数。然后,它通过连接请求路径和查询参数来创建一个新的缓存键,并使用fiber.Ctx
对象的Response().Body()
方法读取响应主体。然后,它使用json.Unmarshal
方法将响应主体列入Post
结构。
如果在删除响应主体时存在错误,则使用fiber.Ctx
对象的JSON方法返回错误响应。
如果没有错误,它使用cache.Cache
对象的集合方法将响应缓存10分钟,并返回零以指示中间件函数已完成处理请求。
现在,让我们为此定义GetPosts()
函数,在主目录中制作一个文件夹routes
。在此制作一个文件routes.go
。
package routes
import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"github.com/gofiber/fiber/v2"
)
type Post struct {
UserID int `json:"userId"`
ID int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func GetPosts(c *fiber.Ctx) error {
id := c.Params("id") // Get the post ID from the request URL parameters
if id == "" {
log.Fatal("Invalid ID")
}
// Fetch the post data from the API
resp, err := http.Get("https://jsonplaceholder.typicode.com/posts/" + id)
if err != nil {
return c.JSON(fiber.Map{"error": err.Error()})
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return c.JSON(fiber.Map{"error": err.Error()})
}
var data Post
err = json.Unmarshal(body, &data)
if err != nil {
return c.JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(data)
}
此功能首先使用c.Params("id")
从URL提取ID参数。如果未提供ID或无效,则会记录致命错误。
然后,它以提供ID作为端点的http GET
请求向https://jsonplaceholder.typicode.com/posts/
API。它在请求期间检查是否有任何错误,并在发生错误时返回错误响应。
然后,使用ioutil.ReadAll()
函数读取响应主体,并使用json.Unmarshal()
将其删除到Post
结构中。如果在解散期间发生错误,则返回错误响应。
最后,该函数使用Post
数据返回JSON响应。然后,该数据由CacheMiddleware()
函数存储在缓存中。
现在,如果我们要确定响应是来自缓存还是API服务器的响应,我们将在响应中添加一个标题,以指示是否从缓存提供了响应。我们将添加一个名为Cache-Status
的自定义标头,并根据是否从缓存提供了响应,将其值设置为HIT
或MISS
。因此,CacheMiddleware()
函数看起来像:
package middleware
import (
"encoding/json"
"time"
"github.com/gofiber/fiber/v2"
"github.com/patrickmn/go-cache"
)
type Post struct {
UserID int `json:"userId"`
ID int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func CacheMiddleware(cache *cache.Cache) fiber.Handler {
return func(c *fiber.Ctx) error {
if c.Method() != "GET" {
// Only cache GET requests
return c.Next()
}
cacheKey := c.Path() + "?" + c.Params("id") // Generate a cache key from the request path and query parameters
// Check if the response is already in the cache
if cached, found := cache.Get(cacheKey); found {
c.Response().Header.Set("Cache-Status", "HIT")
return c.JSON(cached)
}
c.Set("Cache-Status", "MISS")
err := c.Next()
if err != nil {
return err
}
var data Post
cacheKey := c.Path() + "?" + c.Params("id")
body := c.Response().Body()
err = json.Unmarshal(body, &data)
if err != nil {
return c.JSON(fiber.Map{"error": err.Error()})
}
// Cache the response for 10 minutes
cache.Set(cacheKey, data, 10*time.Minute)
return nil
}
}
让我们测试API,在终端中运行go run main.go
,在获得与早期相同的输出后,打开任何API测试工具,例如Postman。
输入url:http://127.0.0.1:8080/posts/1
,然后按Enter。
输出:
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
现在单击“标题”选项,您可以看到Cache-Status
:MISS
。再次按Enter的ID,然后查看Cache-Status
。现在已更改为HIT
。这表明第二次传递相同的参数时,响应是通过缓存发送的。
这是Golang内存内缓存的基本实现。
结论 -
您可以在此处找到本教程的完整代码存储库。
在Golang中,您可以使用内存内存系统实现缓存,就像我们在此博客文章中讨论的那样。通过使用中间件功能,您可以轻松地将缓存集成到Golang Web应用程序中,并减少用户的响应时间。
但是,如果无法正确管理,缓存也可能导致过时的数据。重要的是考虑缓存到期时间并在基础数据更改时更新缓存。
总的来说,缓存可能是您的网络开发工具包的一个很好的补充,我希望这篇博客文章为Golang的内存中心中的内存提供了有用的介绍。
要获取有关Golang概念,项目等的更多信息。并且要保持在教程上的最新信息,请遵循Siddhesh on Twitter和GitHub。
在那之前继续学习,保持建筑