Gin框架操作指南10:服务器与高级功能

官方文档地址(中文):https://gin-gonic.com/zh-cn/docs/
注:本教程采用工作区机制,所以一个项目下载了Gin框架,其余项目就无需重复下载,想了解的读者可阅读第一节:Gin操作指南:开山篇。
本节演示服务器与高级功能,包括运行多个服务;优雅地重启或停止;重定向;支持Let’s-Encrypt;HTTP2-server推送。在开始之前,我们需要在”06服务器与高级功能“目录下打开命令行,执行如下命令来创建子目录:

mkdir  运行多个服务 优雅地重启或停止 重定向 支持Let's-Encrypt HTTP2-server推送

注意:四五两节需要下载安装openssl或者自己拥有一个域名,本文演示使用openssl的情况,openssl的下载与安装还请读者自行搜索,本站一堆。

目录

    • 一、运行多个服务
    • 二、优雅地重启或停止
    • 三、重定向
    • 四、支持Let's-Encrypt
    • 五、HTTP2-server推送

一、运行多个服务

首先执行如下命令安装errgroup包

go get golang.org/x/sync/errgroup

然后填充代码

package mainimport ("log"      // 引入日志包,用于记录错误"net/http" // 引入HTTP包,用于创建HTTP服务器"time"     // 引入时间包,用于设置超时"github.com/gin-gonic/gin"   // 引入Gin框架,用于处理HTTP请求"golang.org/x/sync/errgroup" // 引入errgroup包,用于处理并发任务和错误管理
)// 声明一个errgroup.Group类型的变量,用于管理并发任务
var (g errgroup.Group
)// router01 创建第一个HTTP路由
func router01() http.Handler {e := gin.New()        // 创建一个新的Gin路由e.Use(gin.Recovery()) // 使用Recovery中间件,防止因panic导致服务崩溃// 定义GET请求的路由处理e.GET("/", func(c *gin.Context) {c.JSON( // 返回JSON格式的响应http.StatusOK, // HTTP状态码200gin.H{ // 返回的数据"code":  http.StatusOK,       // 返回的状态码"error": "Welcome server 01", // 返回的消息},)})return e // 返回路由
}// router02 创建第二个HTTP路由
func router02() http.Handler {e := gin.New()        // 创建一个新的Gin路由e.Use(gin.Recovery()) // 使用Recovery中间件,防止因panic导致服务崩溃// 定义GET请求的路由处理e.GET("/", func(c *gin.Context) {c.JSON( // 返回JSON格式的响应http.StatusOK, // HTTP状态码200gin.H{ // 返回的数据"code":  http.StatusOK,       // 返回的状态码"error": "Welcome server 02", // 返回的消息},)})return e // 返回路由
}// main函数是程序的入口
func main() {// 创建第一个HTTP服务器,监听8080端口server01 := &http.Server{Addr:         ":8080",          // 服务器地址和端口Handler:      router01(),       // 设置处理请求的路由ReadTimeout:  5 * time.Second,  // 设置读取超时时间WriteTimeout: 10 * time.Second, // 设置写入超时时间}// 创建第二个HTTP服务器,监听8081端口server02 := &http.Server{Addr:         ":8081",          // 服务器地址和端口Handler:      router02(),       // 设置处理请求的路由ReadTimeout:  5 * time.Second,  // 设置读取超时时间WriteTimeout: 10 * time.Second, // 设置写入超时时间}// 启动第一个服务器的监听g.Go(func() error {return server01.ListenAndServe() // 启动服务器并监听请求})// 启动第二个服务器的监听g.Go(func() error {return server02.ListenAndServe() // 启动服务器并监听请求})// 等待所有服务器的goroutine完成,如果出错则记录并退出if err := g.Wait(); err != nil {log.Fatal(err) // 记录错误并退出程序}
}

效果
在这里插入图片描述

二、优雅地重启或停止

优雅关闭确保在关闭服务器时,正在处理的请求能够完成。这意味着用户不会因为服务器突然停止而遭遇错误,提升用户体验。优雅关闭还允许应用在关闭前执行一些必要的清理操作,例如释放数据库连接、保存缓存、记录日志等,避免数据丢失或资源泄漏。下面演示如何实现。
如果版本低于1.8,可以考虑官方的建议:官方声明。
如果你使用的是 Go 1.8及以上版本,可以使用 http.Server 内置的 Shutdown() 方法优雅地关机:

//go:build go1.8
// +build go1.8package mainimport ("context"   // 引入 context 包,用于控制超时和取消操作"log"       // 引入 log 包,用于记录日志"net/http"  // 引入 net/http 包,用于创建 HTTP 服务器"os"        // 引入 os 包,用于与操作系统进行交互"os/signal" // 引入 os/signal 包,用于接收系统信号"time"      // 引入 time 包,用于时间相关的操作"github.com/gin-gonic/gin" // 引入 Gin 框架
)func main() {// 创建默认的 Gin 路由router := gin.Default()// 定义根路由处理函数router.GET("/", func(c *gin.Context) {// 模拟处理时间time.Sleep(5 * time.Second)// 返回字符串响应c.String(http.StatusOK, "Welcome Gin Server")})// 创建 HTTP 服务器srv := &http.Server{Addr:    ":8080", // 监听地址和端口Handler: router,  // 设置处理请求的路由}// 启动服务器监听请求go func() {// 服务连接if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {// 如果服务出现错误且错误不是因为服务器已关闭,记录错误并退出log.Fatalf("listen: %s\n", err)}}()// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)quit := make(chan os.Signal, 1)    // 创建接收信号的通道signal.Notify(quit, os.Interrupt)  // 监听中断信号<-quit                             // 阻塞直到收到信号log.Println("Shutdown Server ...") // 输出服务器关闭信息// 设置关闭服务器的上下文,并设置超时时间为 5 秒ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel() // 确保在函数退出时取消上下文if err := srv.Shutdown(ctx); err != nil {// 如果服务器关闭时出现错误,记录错误信息log.Fatal("Server Shutdown:", err)}log.Println("Server exiting") // 输出服务器退出信息
}

效果
在这里插入图片描述

三、重定向

创建三个目录:get,post,router
1.GET重定向
cd到get目录

package mainimport ("net/http" // 导入 HTTP 包以使用 HTTP 相关功能"github.com/gin-gonic/gin" // 导入 Gin 框架
)func main() {// 创建一个新的 Gin 引擎实例r := gin.Default()// 定义一个 GET 路由,当访问 /test 时触发该处理函数r.GET("/test", func(c *gin.Context) {// 使用 Redirect 方法进行重定向// http.StatusMovedPermanently 表示 HTTP 301 状态码// 第二个参数是目标 URL,这里重定向到 Google 的首页c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")})// 启动 HTTP 服务器,监听在 8080 端口r.Run(":8080")
}

访问localhost:8080/test即可跳转到Google页面
2.POST重定向
cd到post目录

package mainimport ("net/http" // 导入 HTTP 包以使用 HTTP 相关功能"github.com/gin-gonic/gin" // 导入 Gin 框架
)func main() {// 创建一个新的 Gin 引擎实例r := gin.Default()// 定义一个 GET 路由,当访问 /submit 时触发该处理函数r.GET("/submit", func(c *gin.Context) {// 返回一个 HTML 表单form := `<!DOCTYPE html><html><head><title>Submit Form</title></head><body><h1>Submit to Google</h1><form method="POST" action="/submit/do"><input type="submit" value="Submit"></form></body></html>`c.Header("Content-Type", "text/html") // 设置响应的内容类型为 HTMLc.String(http.StatusOK, form)         // 返回表单})// 定义一个 POST 路由,当提交表单时触发该处理函数r.POST("/submit/do", func(c *gin.Context) {// 使用 Redirect 方法进行重定向// http.StatusFound 表示 HTTP 302 状态码// 第二个参数是重定向目标 URL,这里重定向到 Googlec.Redirect(http.StatusFound, "http://www.google.com")})// 启动 HTTP 服务器,监听在 8080 端口r.Run(":8080")
}

运行,打开浏览器访问http://localhost:8080/submit,会出现提交页面
在这里插入图片描述
点击提交即可跳转到google
3.路由重定向
cd到router目录

package mainimport ("net/http" // 导入 HTTP 包以使用 HTTP 相关功能"github.com/gin-gonic/gin" // 导入 Gin 框架
)func main() {// 创建一个新的 Gin 引擎实例r := gin.Default()// 定义一个 GET 路由,当访问 /test 时触发该处理函数r.GET("/test", func(c *gin.Context) {// 修改请求的 URL 路径,将其重定向到 /test2c.Request.URL.Path = "/test2"// 调用 r.HandleContext 方法,重新处理上下文// 这会根据新的 URL 路径找到对应的处理函数r.HandleContext(c)})// 定义一个 GET 路由,当访问 /test2 时触发该处理函数r.GET("/test2", func(c *gin.Context) {// 返回 JSON 响应,状态码为 200,内容为 {"hello": "world"}c.JSON(http.StatusOK, gin.H{"hello": "world"})})// 启动 HTTP 服务器,监听在 8080 端口r.Run(":8080")
}

在这里插入图片描述
注意,因为这次的路由路径还是和之前一样,所以如果你的浏览器再次跳转到google,清下cookie或把代码中的路由路径改下就行了。

四、支持Let’s-Encrypt

package mainimport ("log""net/http" // 导入 HTTP 包以使用 HTTP 相关功能"github.com/gin-gonic/gin" // 导入 Gin 框架
)func main() {// 创建一个新的 Gin 引擎实例r := gin.Default()// 定义一个 Ping 路由,返回 "pong"r.GET("/ping", func(c *gin.Context) {c.String(http.StatusOK, "pong")})// 启动 HTTPS 服务器,监听在 443 端口err := r.RunTLS(":443", "cert.pem", "key.pem")if err != nil {log.Fatal("Failed to run server: ", err)}
}

执行openssl命令,创建自签名证书

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes

以下是对该命令的解释
-x509: 生成一个自签名的证书。
-newkey rsa:2048: 创建一个新的 RSA 密钥,长度为 2048 位。
-keyout key.pem: 指定生成的私钥文件名。
-out cert.pem: 指定生成的证书文件名。
-days 365: 指定证书有效期为 365 天。
-nodes: 生成的私钥不使用密码保护(不需要输入密码)。
在命令执行过程中,会提示你输入一些信息,如国家、组织名称等,直接按回车跳过即可。
打开浏览器,以谷歌浏览器为例,访问https://localhost/ping,然后按下图操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、HTTP2-server推送

在“HTTP2-server推送”目录下新建目录testdata,并执行如下ssl命令,然后和上一节一样,一直按回车即可

openssl req -x509 -newkey rsa:2048 -keyout ./testdata/server.key -out ./testdata/server.pem -days 365 -nodes

新建main.go,填充代码

package mainimport ("html/template" // 导入模板包以处理 HTML 模板"log"           // 导入日志包以记录错误信息"github.com/gin-gonic/gin" // 导入 Gin 框架
)// 定义一个 HTML 模板
var html = template.Must(template.New("https").Parse(`
<html>
<head><title>Https Test</title><script src="/assets/app.js"></script> <!-- 引入 JavaScript 文件 -->
</head>
<body><h1 style="color:red;">Welcome, Ginner!</h1> <!-- 欢迎信息 -->
</body>
</html>
`))func main() {// 创建一个新的 Gin 引擎实例r := gin.Default()// 设置静态文件目录,允许访问 /assets 路径r.Static("/assets", "./assets")// 设置 HTML 模板r.SetHTMLTemplate(html)// 定义一个 GET 路由,当访问根路径时触发该处理函数r.GET("/", func(c *gin.Context) {// 检查是否支持 HTTP/2 Server Pushif pusher := c.Writer.Pusher(); pusher != nil {// 使用 pusher.Push() 进行服务器推送if err := pusher.Push("/assets/app.js", nil); err != nil {log.Printf("Failed to push: %v", err) // 如果推送失败,记录错误}}// 渲染 HTML 模板并返回给客户端c.HTML(200, "https", gin.H{"status": "success", // 返回状态})})// 监听并在 https://127.0.0.1:8080 上启动服务// 指定 SSL 证书和私钥的路径r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key")
}

效果
访问https://127.0.0.1:8080/,然后步骤和第四节一样,最终返回如下页面
在这里插入图片描述
这里说明一下为什么要访问https://127.0.0.1:8080/而不是https://loaclhost:8080/:
虽然我们前面创建证书时是没有填写字段的,但127.0.0.1 是一种特殊的地址,即回环地址(127.0.0.0 到 127.255.255.255 ),这是系统保留用于本地主机通信的地址,即总是指向本机的地址,所以浏览器不管什么情况都会允许连接,显示警告是因为证书要求。相比之下,localhost 作为主机名,必须匹配证书,浏览器才会允许链接,所以当你访问localhost时,浏览器会显示无法访问此网站。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/56874.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手撕布隆过滤器:原理解析与面试心得

前言 说来话长&#xff0c;话来说长。前些天我投了一些日常实习的简历&#xff0c;结果足足等了两个礼拜才收到面试通知&#xff0c;看来如今的行情确实是挺紧张的。当时我是满怀信心去的&#xff0c;心想这次一定要好好拷打面试官一番&#xff0c;结果没想到&#xff0c;自我…

腰背肌筋膜炎有哪些治疗方法

腰背肌筋膜炎主要表现为腰背部的疼痛、酸胀、僵硬、活动受限等症状。在疾病初期&#xff0c;症状可能相对较轻&#xff0c;通过休息、保暖、适当的物理治疗等&#xff0c;往往可以缓解症状&#xff0c;此时病情不算严重。如果患者不重视&#xff0c;继续保持不良的生活习惯&…

微服务架构 --- 使用RabbitMQ进行异步处理

目录 一.什么是RabbitMQ&#xff1f; 二.异步调用处理逻辑&#xff1a; 三.RabbitMQ的基本使用&#xff1a; 1.安装&#xff1a; 2.架构图&#xff1a; 3.RabbitMQ控制台的使用&#xff1a; &#xff08;1&#xff09;Exchanges 交换机&#xff1a; &#xff08;2&#…

什么是不同类型的微服务测试?

大家好&#xff0c;我是锋哥。今天分享关于【什么是不同类型的微服务测试&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; 什么是不同类型的微服务测试&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 微服务架构中的测试可以分为多种类…

WPF基础权限系统

一.开发环境 VisualStudio 2022NET SDK 8.0Prism 版本 8.1.97Sqlite 二. 功能介绍 WPF 基础权限系统&#xff0c;是一个支持前后端分离设计的 客户端(C/S)项目&#xff0c;该示例项目前端xaml使用UI库 &#xff0c;Material Design Themes UI 来构建用户界面&#xff0c;确保…

【into outfile写文件】

简介 select * from user into outfile C:/Users/ichunqiu/Desktop/PhpStudy2018/PHPTutorial/WWW/1.txt;用法的意思就是把user表中查询到的所有字段都导出到1.txt文件中 我们之前还有学到dumpfile&#xff0c;单是它只能导出一条数据 写入shell 测试注入点 usernameadmin&…

【工具】使用perf抓取火焰图

背景 当程序存在cpu性能问题时&#xff0c;我们需要找到是哪个函数占用较多的CPU&#xff0c;也就是找出热点函数&#xff1b;perf的火焰图就是这个用途 安装 在Linux系统中&#xff0c;perf 是 Linux 内核提供的性能分析工具&#xff0c;它通常包含在内核源代码包中。大多数…

编码方式知识整理【ASCII、Unicode和UTF-8】

编码方式 一、ASCII编码二、Unicode 编码三、UTF-8编码四、GB2312编码五、GBK编码 计算机中对数据的存储为二进制形式&#xff0c;但采用什么样的编码方式存储&#xff0c;效率更高。主要编码方式有 ASCII、Unicode、UTF-8等。 英文一般为1个字节&#xff0c;汉字一般为3个字节…

Linux 线程互斥

1.相关背景概念 临界资源&#xff1a;多线程执行流共享的资源就叫做临界资源 临界区&#xff1a;每个线程内部&#xff0c;访问临界资源的代码&#xff0c;就叫做临界区 #include <iostream> #include <pthread.h> #include <string> #include <vector…

mac安装jdk8

这里写自定义目录标题 一、下载JDK8二、安装JDK8三、配置环境变量3.1 找到JDK安装目录3.2 打开终端&#xff1a;3.3 输入如下配置&#xff1a;3.3 查看配置是否成功&#xff1a; 一、下载JDK8 oracle官网下载或从下面链接获取 https://download.csdn.net/download/qq_44107684…

【小沐学Golang】基于Go语言搭建静态文件服务器

文章目录 1、简介2、安装2.1 安装版2.2 压缩版 3、基本操作3.1 go run3.2 go build3.3 go install3.4 go env3.5 go module 4、文件服务器4.1 filebrowser4.2 gohttpserver4.3 goFile 5、FAQ5.1 go.mod 为空5.2 超时 结语 1、简介 https://golang.google.cn/ Go语言诞生于2007…

day02 -- docker

1.docker的介绍 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使…

●day 35 动态规划part01

第九章 动态规划part01 动态规划的类别 理论基础 动态规划下五步曲&#xff1a; 1、确定dp数组&#xff08;dp table&#xff09;以及下标的含义 2、确定递推公式 3、dp数组如何初始化 4、确定遍历顺序 5、打印dp数组 代码随想录 斐波那契数 代码随想录 动态规划5部曲 cla…

高级语言源程序转换为可执行目标文件

将高级语言源程序转换为可执行目标文件的过程通常包括以下几个主要步骤&#xff1a; ​ 1. 预处理&#xff08;Preprocessing&#xff09;&#xff1a; 由谁完成预处理器&#xff08;cpp&#xff09;操作处理源代码中的预处理指令&#xff08;如宏定义、文件包含、条件编译等&…

Linux——动态卷的管理

确保已经设置了对应的动态卷的驱动&#xff08;provisioner 制备器&#xff09;基于动态驱动创建对应的存储类创建PVC &#xff08;PVC 将会自动根据大小、访问模式等创建PV&#xff09;Pod的spec 中通过volumes 和 volumemounts 来完成pvc 的绑定和pvc对应pv的挂载删除pod 不…

Linux网络编程(七)-TCP协议客户端及代码实现

1.TCP的客户端代码流程简述 这一章将为大家讲解Socket通信中客户端的实现过程&#xff0c;还是先上图&#xff0c;请大家了解客户端的步骤 可以看到&#xff0c;相比服务端&#xff0c;客户端的步骤简单的很多。事实上这种情况比较多&#xff0c;比如一个服务端会有多个客户端…

JMeter模拟并发请求

PostMan不是严格意义上的并发请求工具&#xff0c;实际是串行的&#xff0c;如果需要测试后台接口并发时程序的准确性&#xff0c;建议采用JMeter工具。 案例&#xff1a;JMeter设置20个并发卖票请求&#xff0c;查看后台是否存在超卖的情况 方式一&#xff1a;一共10张票&…

TrickMo 安卓银行木马新变种利用虚假锁屏窃取密码

近期&#xff0c;研究人员在野外发现了 TrickMo Android 银行木马的 40 个新变种&#xff0c;它们与 16 个下载器和 22 个不同的命令和控制&#xff08;C2&#xff09;基础设施相关联&#xff0c;具有旨在窃取 Android 密码的新功能。 Zimperium 和 Cleafy 均报道了此消息。 …

编写一个通用的i2c控制器驱动框架

往期内容 I2C子系统专栏&#xff1a; I2C&#xff08;IIC&#xff09;协议讲解-CSDN博客SMBus 协议详解-CSDN博客I2C相关结构体讲解:i2c_adapter、i2c_algorithm、i2c_msg-CSDN博客内核提供的通用I2C设备驱动I2c-dev.c分析&#xff1a;注册篇内核提供的通用I2C设备驱动I2C-dev.…

时空数据时序预测模型: HA、VAR、GBRT、GCN、DCRNN、FCCF、ST-MGCN

HA (Historical Average) HA (Historical Average&#xff0c;历史平均模型) 是一种基础的时间序列预测方法&#xff0c;通常用于预测具有周期性或季节性规律的数据。它通过计算历史上同一时间段的平均值来预测未来值&#xff0c;假设数据会遵循某种周期性的变化模式。以下是对…