文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

用Go实现一个带缓存的REST API服务端

2024-11-30 03:34

关注

REST API 的设计目的是创建简单、可伸缩、可维护且具有良好可读性的接口, 以促进客户端和服务器之间的有效通信, 通过使用HTTP协议和一组统一的设计原则, REST API在实现上具备一些特定的属性:

2.REST API服务端设计

下面我将使用Go语言来设计一个REST API的服务端, 这里的模拟场景是通过服务端来对外提供文章的增、删、查服务, 文章的查询方式包括两种: 1.查询服务器所有文章内容。2.根据文章ID查询某篇文章的内容。

文章的属性包括三个字段: 文章ID、文章、文章内容, 这里可以用一个结构体表示:

type Article struct {
  ID string `json:"id,omitempty"`
  Title string `json:"title,omitempty"`
  Content string `json:"content,omitempty"`
}

由于我们设计了四个功能接口, 将其转换成接口代码框架如下:

// 获取所有文章接口
func GetArticles(w http.ResponseWriter, r *http.Request) {
     ...
}

// 获取单篇文章接口
func GetArticle(w http.ResponseWriter, r *http.Request) {
     ...
}

// 创建文章接口
func CreateArticle(w http.ResponseWriter, r *http.Request) {
     ...
}

// 删除文章接口
func DeleteArticle(w http.ResponseWriter, r *http.Request) {
     ...
}

3.功能代码实现

首先来实现获取所有文章的接口, 具体参考代码如下:

// 获取所有文章
func GetArticles(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json")

  // 尝试从缓存中获取文章列表
  if cachedArticles, found := articleCache.Load("all"); found {
    json.NewEncoder(w).Encode(cachedArticles)
    return
  }

  // 从原始数据源获取文章列表
  json.NewEncoder(w).Encode(Articles)

  // 将文章列表存入缓存
  articleCache.Store("all", Articles)
}

获取所有文章首先是尝试从缓存中获取文章列表, 缓存cachedArticles这里实际是一个sync.Map类型的变量, 支持并发安全, 如果找到的话, 直接序列化成JSON的格式返回。如果缓存中没有找到, 则从原始数据源中获取文章列表(实际应用中应该是从数据库中获取)并序列化成JSON返回。并把该文章列表存入缓存之中。

接下来实现第二个接口,通过文章ID来查询, 实现参考代码如下:

// 获取单篇文章
func GetArticle(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json")
  params := mux.Vars(r)

  // 尝试从缓存中获取单个文章
  if cachedArticle, found := articleCache.Load(params["id"]); found {
    json.NewEncoder(w).Encode(cachedArticle)
    return
  }

  // 从原始数据源获取单个文章
  for _, article := range Articles {
    if article.ID == params["id"] {
      json.NewEncoder(w).Encode(article)
      // 将单个文章存入缓存
      articleCache.Store(params["id"], article)
      return
    }
  }
  json.NewEncoder(w).Encode(&Article{})
}

首先将传入的ID参数在缓存中进行查找, 找到则直接返回JSON数据。如果没有找到则继续在文章列表中查找, 并将单篇文章存入缓存。

创建文章接口参考代码如下:

// 创建文章
func CreateArticle(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json")
  var article Article
  _ = json.NewDecoder(r.Body).Decode(&article)
  Articles = append(Articles, article)

  // 清除所有文章缓存
  articleCache.Delete("all")

  json.NewEncoder(w).Encode(Articles)
}

创建文章列表需要注意的是, 这里为了维护缓存一致性,避免脏数据, 对缓存进行了清空, 以便下次GetArticles()时更新最新的缓存。

同理也不难实现删除文章的接口:

// 删除文章
func DeleteArticle(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json")
  params := mux.Vars(r)

  // 清除单个文章缓存
  articleCache.Delete(params["id"])

  for index, article := range Articles {
    if article.ID == params["id"] {
      Articles = append(Articles[:index], Articles[index+1:]...)
      break
    }
  }

  // 清除所有文章缓存
  articleCache.Delete("all")

  json.NewEncoder(w).Encode(Articles)
}

最后, 在main函数中, 我们需要往列表中添加一些数据来模拟服务端保存的文章数, 并且定义四个接口的路由, 整体代码如下:

package main

import (
  "encoding/json"
  "log"
  "net/http"
  "sync"

  "github.com/gorilla/mux"
)

// Article 结构体表示 API 中的数据模型
type Article struct {
  ID string `json:"id,omitempty"`
  Title string `json:"title,omitempty"`
  Content string `json:"content,omitempty"`
}

// Articles 数组用于存储文章数据
var Articles []Article
var articleCache sync.Map

// 获取所有文章
func GetArticles(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json")

  // 尝试从缓存中获取文章列表
  if cachedArticles, found := articleCache.Load("all"); found {
    json.NewEncoder(w).Encode(cachedArticles)
    return
  }

  // 从原始数据源获取文章列表
  json.NewEncoder(w).Encode(Articles)

  // 将文章列表存入缓存
  articleCache.Store("all", Articles)
}

// 获取单个文章
func GetArticle(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json")
  params := mux.Vars(r)

  // 尝试从缓存中获取单个文章
  if cachedArticle, found := articleCache.Load(params["id"]); found {
    json.NewEncoder(w).Encode(cachedArticle)
    return
  }

  // 从原始数据源获取单个文章
  for _, article := range Articles {
    if article.ID == params["id"] {
      json.NewEncoder(w).Encode(article)
      // 将单个文章存入缓存
      articleCache.Store(params["id"], article)
      return
    }
  }
  json.NewEncoder(w).Encode(&Article{})
}

// 创建文章
func CreateArticle(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json")
  var article Article
  _ = json.NewDecoder(r.Body).Decode(&article)
  Articles = append(Articles, article)

  // 清除所有文章缓存
  articleCache.Delete("all")

  json.NewEncoder(w).Encode(Articles)
}

// 删除文章
func DeleteArticle(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json")
  params := mux.Vars(r)

  // 清除单个文章缓存
  articleCache.Delete(params["id"])

  for index, article := range Articles {
    if article.ID == params["id"] {
      Articles = append(Articles[:index], Articles[index+1:]...)
      break
    }
  }

  // 清除所有文章缓存
  articleCache.Delete("all")

  json.NewEncoder(w).Encode(Articles)
}


func main() {
  // 初始化数据
  Articles = append(Articles, Article{ID: "1", Title: "Article 1", Content: "Content 1"})
  Articles = append(Articles, Article{ID: "2", Title: "Article 2", Content: "Content 2"})

  // 创建路由器
  router := mux.NewRouter()

  // 定义路由处理程序
  router.HandleFunc("/articles", GetArticles).Methods(http.MethodGet)
  router.HandleFunc("/articles/{id}", GetArticle).Methods(http.MethodGet)
  router.HandleFunc("/articles", CreateArticle).Methods(http.MethodPost)
  router.HandleFunc("/articles/{id}", DeleteArticle).Methods(http.MethodDelete)

  // 启动服务器
  log.Fatal(http.ListenAndServe(":8080", router))
}

4.实际运行效果

在本地运行服务端, 服务端将在本地监听8080端口, 通过浏览器输入: http://127.0.0.1:8080/articles, 该接口将获取所有文章,如图:

通过API接口通过文章ID查询某一篇文章,接口请求如下:

新增一条新文章是POST请求, 这里主要通过Apifox发送POST请求,如图:

从返回的结果来看, 成功添加了一条新记录, 再次使用获取全部文章接口看一下,如图:

新记录确实添加成功。

最后, 还是通过Apifox,我们发送一个删除ID为2的文章请求,如图:

从Apifox返回的结果来看,确实删除成功了,  现在再获取一下全部文章,如图:

所有接口全部验证成功。

来源:二进制空间安全内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯