目录

RESTful API服务器

1. REST Web 框架选择

2. 安装Gin

3. 第一个Gin程序

4. 路由模块化

5. 编译源码

API 服务器健康状态自检

1. 服务器健康有哪些?

2. 定义路由分组用于服务器健康检查

3. 服务器健康检查实现

4. 安装依赖并测试

5. 测试

6. 启动apiserver时自检

7. 测试


RESTful API服务器

1. REST Web 框架选择

要编写一个 RESTful 风格的 API 服务器,首先需要一个 RESTful Web 框架,经过调研选则了GitHub star 数最多的Gin。采用轻量级的 Gin 框架,具有如下优点: 高性能 、 扩展性强 、 稳定性强 、相对而言比较 简洁 (查看 性能对比)。关于 Gin 的更多介绍可以参考 Golang 微框架 Gin 简介。
Gin 是使用 Go/golang 语言实现的 HTTP Web 框架。接口简洁,性能极高。截止 1.4.0 版本,包含测试代码,仅14K,其中测试代码 9K 左右,也就是说框架源码仅 5K 左右。
Gin 特性
快速:路由不使用反射,基于Radix树,内存占用少。
中间件:HTTP请求,可先经过一系列中间件处理,例如:Logger,Authorization,GZIP等。这个特性和NodeJs 的 Koa 框架很像。中间件机制也极大地提高了框架的可扩展性。
异常处理:服务始终可用,不会宕机。Gin 可以捕获 panic,并恢复。而且有极为便利的机制处理HTTP请求过程中发生的错误。
JSON:Gin可以解析并验证请求的JSON。这个特性对 Restful API 的开发尤其有用。
路由分组:例如将需要授权和不需要授权的API分组,不同版本的API分组。而且分组可嵌套,且性能不受影响。
渲染内置:原生支持JSON,XML和HTML的渲染。

2. 安装Gin

手动安装Gin
go get -u -v github.com/gin-gonic/gin
-v :打印出被构建的代码包的名字 -u :已存在相关的代码包,强行更新代码包及其依赖包

3. 第一个Gin程序

构建了一个测试账号系统(后面统称为 apiserver )
创建apiserver文件夹,在里新建文件 main.go 。
这里的文件名可以不叫main.go,但是由于它是主运行文件,所以按惯例可以命名为main.go
apiserver/main.go
// 声明当前文件属于哪个包,如果是主文件,则写成main
package main // 导入gin
import "github.com/gin-gonic/gin" func main() { // 生成了一个实例,这个实例即 WSGI 应用程序 g := gin.Default() // 声明了一个路由/ 及对应的处理函数 g.GET("/", func(c *gin.Context) { c.String(200, "Hello, scRouter") })// 让应用运行在本地服务器上,默认监听端口是 8090g.Run(":8090") // listen and serve on 0.0.0.0:8090
}
初始化
go mod init apiserver
go mod tidy
运行
$ go run main.go
[GIN-debug] GET / --> main.main.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8090
Apipost6访问192.168.149.150:8090
常见问题
在本地浏览器上访问Linux服务器上启动的服务不成功,成功访问的条件:
        1. 网络通:即ip能ping通,且端口通这里一般大概率会是防火墙禁止了端口访问,所以可以将防火墙关闭。
        2. 端口监听正常:确保端口是启动的

# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 993/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1275/master
tcp6 0 0 :::8000 :::* LISTEN 3351/main
tcp6 0 0 :::22 :::* LISTEN 993/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1275/master

4. 路由模块化

main.go 中的 main() 函数是 Go 程序的入口函数
在 main() 函数中主要做一些配置文件解析、程序初始化和路由加载之类的事情,最终调用http.ListenAndServe() 在指定端口启动一个 HTTP 服务器。
本案例是一个简单的 HTTP 服务器,仅初始化一个 Gin 实例,加载路由模块并启动 HTTP 服务器。
为什么要模块化

想像一下,如果一个项目2000行代码,全部写在一个文件中会有什么效果?
模块化的主要目的是将不同的功能拆分到不同的目录和文件,会让整个项目结构上会更清晰。 后期维护会更便捷。
创建路由模块
目录结构
[root@linuxserver apiserver]# tree
.
├── go.mod
├── go.sum
├── main.go
└── router └── router.go
1 directory, 4 files
创建目录router,再编写router.go文件
mkdir router
路由文件:apiserver/router/router.go
package router
import ( "github.com/gin-gonic/gin"
)// Load中负责加载中间件middlewares、路由routes和handlers
func Load(g *gin.Engine, mw ...gin.HandlerFunc) *gin.Engine { // 添加路由 g.GET("/", func(c *gin.Context) { c.String(200, "Hello, scRputer") })// 加载中间件 g.Use(mw...) return g
}router目录负责路由相关内容,如定义路由及路由处理函数,路由加载的中间件等
导入并引用路由模块
添加引入路由模块代码:apiserver/main.go
// 声明当前文件属于哪个包,如果是主文件,则写成main
package main
// 导入gin
import ( // 导入路由模块"apiserver/router" "github.com/gin-gonic/gin"
)func main() { // 生成了一个实例,这个实例即 WSGI 应用程序 g := gin.Default() //-modify here- 加载路由 router.Load( // Cores. g, )// 让应用运行在本地服务器上,默认监听端口是 8080g.Run(":8090") // listen and serve on 0.0.0.0:8090
}

测试1配置NoRoute的处理                                                                                                                       客户端在访问时,难免会输入错误的url,所以可以添加NoRoute处理404请求,apiserver/route/route.go

package router
import ( "github.com/gin-gonic/gin" "net/http"
)
// Load中负责加载中间件middlewares、路由routes和handlers
func Load(g *gin.Engine, mw ...gin.HandlerFunc) *gin.Engine { // 404 Handler.处理404g.NoRoute(func(c *gin.Context) { c.String(http.StatusNotFound, "url not found") })// 添加路由 g.GET("/", func(c *gin.Context) { c.String(200, "Hello, scRouter") })return g
}

测试2

5. 编译源码

进入 apiserver 目录编译源代码

$ gofmt -w .
// Vet 检查 Go 源码并报告可疑的构造
$ go vet .
// 用于编译代码,在编译过程中,会同时编译与之相关联的包
$ go build -v .编译后的二进制文件存放在当前目录,名字跟目录名相同: apiserver 或 apiserver.exe 。
这个文件可以直接运行,不与源代码依赖
./apiserver

API 服务器健康状态自检

1. 服务器健康有哪些?

  • 磁盘空间

  • CPU状态

  • MEM状态

  • 服务状态等

2. 定义路由分组用于服务器健康检查

由于后期我们会实现很多路由对应的处理函数,如果量大的话,router文件会变得非常大

因此,我们也可以将处理函数放到handler目录中

”apiserver/handler/sd“ 此目录将用于保存服务器检查相关处理函数

注意:短小的处理函数可以直接编写匿名函数放在router中,长函数建议拆分

apiserver/router/router.go

    // 加载模块-处理函数模块化"apiserver/handler/sd"// 在Load函数中添加    //  -modify here- 添加健康检查的handlersvcd := g.Group("/sd"){   svcd.GET("/health", sd.HealthCheck)svcd.GET("/disk", sd.DiskCheck)svcd.GET("/cpu", sd.CPUCheck)svcd.GET("/ram", sd.RAMCheck)}

该代码块定义了一个叫 sd 的路由分组,在该分组下注册了 /health/disk/cpu/ram HTTP 路径,分别路由到 sd.HealthChecksd.DiskChecksd.CPUChecksd.RAMCheck 函数。                 sd 分组主要用来检查 API Server 的状态:健康状况、服务器硬盘、CPU 和内存使用量。         main() 函数通过调用 router.Load 函数来加载路由,路由映射到具体的处理函数

3. 服务器健康检查实现

apiserver/handler/sd/check.go

编写几个检查函数

package sdimport ("fmt""net/http""github.com/gin-gonic/gin""github.com/shirou/gopsutil/cpu""github.com/shirou/gopsutil/disk""github.com/shirou/gopsutil/load""github.com/shirou/gopsutil/mem"
)// 定义常量
const (B  = 1KB = 1024 * BMB = 1024 * KBGB = 1024 * MB
)// HealthCheck shows `OK` as the ping-pong result.
func HealthCheck(c *gin.Context) {message := "OK"// http.StatusOK => 所有HTTP状态码都对应到一个名字 (源码)c.String(http.StatusOK, "\n"+message)
}// DiskCheck checks the disk usage.
func DiskCheck(c *gin.Context) {// 可查看disk.Usage的源代码,此处有2个返回值,*UsageStat, errou, _ := disk.Usage("/")usedMB := int(u.Used) / MBusedGB := int(u.Used) / GBtotalMB := int(u.Total) / MBtotalGB := int(u.Total) / GBusedPercent := int(u.UsedPercent)status := http.StatusOKtext := "OK"if usedPercent >= 95 {status = http.StatusInternalServerErrortext = "CRITICAL"} else if usedPercent >= 90 {status = http.StatusTooManyRequeststext = "WARNING"}message := fmt.Sprintf("%s - Free space: %dMB (%dGB) / %dMB (%dGB) | Used: %d%%", text, usedMB, usedGB, totalMB, totalGB, usedPercent)c.String(status, "\n"+message)
}// CPUCheck checks the cpu usage.
func CPUCheck(c *gin.Context) {cores, _ := cpu.Counts(false)a, _ := load.Avg()l1 := a.Load1l5 := a.Load5l15 := a.Load15status := http.StatusOKtext := "OK"if l5 >= float64(cores-1) {status = http.StatusInternalServerErrortext = "CRITICAL"} else if l5 >= float64(cores-2) {status = http.StatusTooManyRequeststext = "WARNING"}message := fmt.Sprintf("%s - Load average: %.2f, %.2f, %.2f | Cores: %d", text, l1, l5, l15, cores)c.String(status, "\n"+message)
}// RAMCheck checks the disk usage.
func RAMCheck(c *gin.Context) {u, _ := mem.VirtualMemory()usedMB := int(u.Used) / MBusedGB := int(u.Used) / GBtotalMB := int(u.Total) / MBtotalGB := int(u.Total) / GBusedPercent := int(u.UsedPercent)status := http.StatusOKtext := "OK"if usedPercent >= 95 {status = http.StatusInternalServerErrortext = "CRITICAL"} else if usedPercent >= 90 {status = http.StatusTooManyRequeststext = "WARNING"}message := fmt.Sprintf("%s - Free space: %dMB (%dGB) / %dMB (%dGB) | Used: %d%%", text, usedMB, usedGB, totalMB, totalGB, usedPercent)c.String(status, "\n"+message)
}

4. 安装依赖并测试

mod tidy 会自动检查依赖并下载需要的内容,非常nice
```
go mod tidy
```
这里主要是安装了:
```
go get github.com/shirou/gopsutil/cpu
go get github.com/shirou/gopsutil/disk
go get github.com/shirou/gopsutil/load
go get github.com/shirou/gopsutil/mem
```

5. 测试

命令行测试:

# curl http://localhost:8090/sd/healthOK

ApiPost测试:

6. 启动apiserver时自检

上面我们已经实现了几个接口用于获取服务器状态,但是,它需要我们主动访问才能获取状态,那么我们如何能在有问题时,直接收到提醒呢?定时任务/监控系统:编写监控脚本,有问题时提醒

启动服务时:主动检查,有问题直接停掉服务,提醒管理员

有时候 API 进程起来不代表 API 服务器正常,如API 进程存在,但是服务器却不能对外提供服务。因此在启动 API 服务器时,如果能够最后做一个自检会更好些。

在 apiserver 中添加了自检程序,通过自检可以最大程度地保证启动后的 API 服务器处于健康状态。

apiserver/main.go

定义pingServer用于检查/sd/health是否正常访问

// pingServer pings the http server to make sure the router is working.
func pingServer() error {for i := 0; i < 10; i++ {// 请求/sd/health => Get返回值有两个resp, err := http.Get("http://127.0.0.1:8090" + "/sd/health")log.Print("Waiting for the router, retry in 1 second.")// 如果返回200,则表示启动成功,直接返回nilif err == nil && resp.StatusCode == 200 {return nil}// 否则1秒后重试log.Print("Waiting for the router, retry in 1 second.")time.Sleep(time.Second)}// 尝试10次,均失败则返回一个错误return errors.New("Cannot connect to the router.")
}
  • pingServer() 函数中,http.Gethttp://127.0.0.1:8080/sd/health 发送 HTTP GET 请求

  • 如果函数正确执行并且返回的 HTTP StatusCode 为 200,则说明 API 服务器可用。

  • 如果超过指定次数,服务还是不能访问,pingServer会 返回errors,表示API服务器不可用。

apiserver/main.go 调用pingServer检查服务是否正常func main() {...// 调用协程函数,检查服务健康状态go func() {if err := pingServer(); err != nil {log.Fatal("The router has no response, or it might took too long to start up.", err)}log.Print("The router has been deployed successfully.")}()// 让应用运行在本地服务器上,默认监听端口是 8080g.Run(":8090") // listen and serve on 0.0.0.0:8090
}
  • 在启动 HTTP 端口前 go 一个 pingServer 协程(后台并行执行的一个任务)

  • 启动 HTTP 端口后,该协程不断地 ping /sd/health 路径

  • 如果成功,则输出部署成功提示

  • 如果失败次数超过一定次数,则终止 HTTP 服务器进程

7. 测试

GO语言04(简单的RESTful API服务器,API 服务器健康状态自检)相关推荐

  1. mysql例子 restful_Gin实战:Gin+Mysql简单的Restful风格的API

    我们已经了解了Golang的Gin框架.对于Webservice服务,restful风格几乎一统天下.Gin也天然的支持restful.下面就使用gin写一个简单的服务,麻雀虽小,五脏俱全.我们先以一 ...

  2. Gin实战:Gin+Mysql简单的Restful风格的API

    我们已经了解了Golang的Gin框架.对于Webservice服务,restful风格几乎一统天下.Gin也天然的支持restful.下面就使用gin写一个简单的服务,麻雀虽小,五脏俱全.我们先以一 ...

  3. 启动服务错误5拒绝访问_【Go API 开发实战 5】基础1:启动一个最简单的 RESTful API 服务器...

    启动一个最简单的 RESTful API 服务器 本节核心内容 启动一个最简单的 RESTful API 服务器 设置 HTTP Header API 服务器健康检查和状态查询 编译并测试 API 本 ...

  4. 【Go API 开发实战 5】基础1:启动一个最简单的 RESTful API 服务器

    本节核心内容 启动一个最简单的 RESTful API 服务器 设置 HTTP Header API 服务器健康检查和状态查询 编译并测试 API 本小节源码下载路径:demo01 可先下载源码到本地 ...

  5. C语言实现简单的Web服务器

    C语言实现简单的Web服务器 一. 基础知识 二. 详细设计 三. 代码实现 四. 功能测试 五. 内容总结 个人博客:coonaa.cn [本文博客同步地址] 在之前的文章中使用C语言实现基于TCP ...

  6. C语言API接口开发,腾讯云服务器 API C语言接口

    腾讯云服务器的官方API和文档非常详尽,但是对于嵌入式设备还不是很友好,为了在项目中开发一个发送短信的功能,写了一个腾讯云服务器的客户端api,抽取了其中框架部分: 腾讯云服务器 API处理的流程: ...

  7. azure api 管理_具有Azure功能的无服务器API

    azure api 管理 在这篇文章中,我将研究一个非常简单的用例. 在执行部署管道时, FlexDeploy可能会产生一些应被批准或拒绝的人工任务. 例如,某人必须批准对生产环境的部署. 可以在Fl ...

  8. 具有Azure功能的无服务器API

    在这篇文章中,我将研究一个非常简单的用例. 在执行部署管道时, FlexDeploy可能会产生一些应被批准或拒绝的人工任务. 例如,某人必须批准对生产环境的部署. 可以在FlexDeploy UI中或 ...

  9. web api json_有关使用JSON Web令牌保护无服务器API的速成班

    web api json What a mouthful of a title. Wouldn't you agree? In this walkthrough you'll learn about ...

  10. php yii2 api框架,Yii2框架制作RESTful风格的API快速入门教程

    先给大家说下什么是REST restful REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Ro ...

最新文章

  1. 【Linux 内核】进程管理 task_struct 结构体 ① ( task_struct 结构体引入 | task_struct 代码示例 )
  2. Java 13,最新最全新特性解读
  3. QScrollArea滚动条
  4. python输出10行带标号的hello、world_Python输出hello world(各行命令详解)
  5. (一)密码学之数论基础
  6. 信号与线性系统管致中第六版pdf_第五讲 信号流图
  7. 格式工厂采样率,比特率怎样设置才能使音频声音大容量小
  8. Linux: 查看网络流量
  9. KVM详解,太详细太深入了,经典
  10. mapgis 转换为CAD格式图形 显示不出来的处理
  11. IDEA中一直indexing问题
  12. 交换机中的生成树,是什么树?
  13. 科研新手该如何找到合适的文献?| 开启科研之路(王威教授)
  14. Coursera课程自然语言处理(NLP)笔记整理(一)
  15. 2021-01-25广州大学ACM寒假训练赛解题心得
  16. matlab mex命令,matlab 调用mex
  17. 对自定义类实现排序的四种方法
  18. Java面试题(十九) 细说线程池秘境“七大参数”护法的身世
  19. H5+CSS3 背景图毛玻璃效果实现方案
  20. 微.解析FoMo3D及其赝品(含智能合约解释)

热门文章

  1. Open JDK patched with font fix
  2. 写出linux命令的功能,练习一LINUX命令测试题1
  3. 通过Socket实现群聊的思路
  4. 二本学生四年的求职经历
  5. 计算机局域网的组网,计算机局域网组网方案设计(精选).doc
  6. npm publish常见问题
  7. 明源软件热忱欢迎您的加入---2011年校园招聘
  8. 电脑连上手机热点后上不了网
  9. 【SpringBoot】63、SpringBoot中教你手把手封装自己的starter(xxl-job-spring-boot-starter)
  10. oracle rman optimization,Oracle rman备份的使用(转)