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 main

import (
	"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状态码200
			gin.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状态码200
			gin.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.8

package main

import (
	"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 main

import (
	"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 main

import (
	"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") // 设置响应的内容类型为 HTML
		c.String(http.StatusOK, form)         // 返回表单
	})

	// 定义一个 POST 路由,当提交表单时触发该处理函数
	r.POST("/submit/do", func(c *gin.Context) {
		// 使用 Redirect 方法进行重定向
		// http.StatusFound 表示 HTTP 302 状态码
		// 第二个参数是重定向目标 URL,这里重定向到 Google
		c.Redirect(http.StatusFound, "http://www.google.com")
	})

	// 启动 HTTP 服务器,监听在 8080 端口
	r.Run(":8080")
}

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

package main

import (
	"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 路径,将其重定向到 /test2
		c.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 main

import (
	"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 main

import (
	"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 Push
		if 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时,浏览器会显示无法访问此网站。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SICK系列激光雷达单点测距仪DT80-311111+SIG200配置和通信

文章目录 一、硬件连接与SOPAS连接测距仪二、从SOPAS读取数据三、通过JSON获取数据1. 使用Postman测试接口2. 通过代码实现 一、硬件连接与SOPAS连接测距仪 首先硬件设备连接如下&#xff1a; 电源厂家应该是不提供&#xff0c;需要自行解决。 安装完成后需要使用sick的SOPAS…

增量知识 (Incremental Knowledge, IK)

在语义通信系统中&#xff0c;增量知识&#xff08;IK, Incremental Knowledge&#xff09;是一种增强数据传输效率和可靠性的技术&#xff0c;特别是用于混合自动重传请求&#xff08;HARQ, Hybrid Automatic Repeat reQuest&#xff09;机制时。它的核心思想是在传输失败后&a…

图像中的融合

图像显示函数 def img_show(name, img):"""显示图片:param name: 窗口名字:param img: 图片对象:return: None"""cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyAllWindows()图像读取与处理 读取图片 cloud cv2.imread(bg.jpg) fish cv2.…

【uni-app】HBuilderX安装uni-ui组件

目录 1、官网找到入口 2、登录帐号 3、打开HuilderX 4、选择要应用的项目 5、查看是否安装完成 6、按需安装 7、安装完毕要重启 8、应用 前言&#xff1a;uniapp项目使用uni-ui组件方式很多&#xff0c;有npm安装等&#xff0c;或直接创建uni-ui项目&#xff0c;使用un…

threejs-光线投射实现3d场景交互事件

一、介绍 1.属性 // 创建射线 const raycaster new three.Raycaster() // 创建鼠标向量(保存鼠标点击位置) const mouse new three.Vector2() // 创建点击事件 window.addEventListener(click,(event)>{// 获取鼠标点击位置mouse.x (event.clientX / window.innerWidt…

HAL+M4学习记录_7

一、TIM 记录学习HAL配置TIM定时器 1.1 简介 TIM&#xff08;timer&#xff09;定时器&#xff0c;16位或32位&#xff08;TIM2和TIM5&#xff09;计数器、预分频器&#xff08;16位&#xff09;、自动重装寄存器的时基单元&#xff1b;可对输入时钟进行计数&#xff0c;在计数…

PyQt 入门教程(3)基础知识 | 3.1、使用QtDesigner创建.ui文件

文章目录 一、使用QtDesigner创建.ui文件1、创建.ui文件2、生成.py文件3、使用新生成的.py文件4、编辑新生成的.py文件 一、使用QtDesigner创建.ui文件 1、创建.ui文件 打开PyCharm&#xff0c;使用自定义外部工具QtDesigner创建mydialog.ui文件&#xff0c;如下&#xff1a; …

finalshell连接navicat数据库

一、安装mysql数据库 这个安装在另外一篇里 超详细的finalshell安装数据库以及数据库的基本操作-CSDN博客https://blog.csdn.net/cfjbcg/article/details/142990671 二、连接 说明root这个用户连接&#xff0c;是有权限的限制的----》修改权限 use mysql pdate user set hos…

测试教程分享

前几年在腾讯课堂上发布了不少课程&#xff0c;后来腾讯课堂改革&#xff0c;要收会员费&#xff0c;课程还要抽提程&#xff0c;这么下来就相当于白干了。就放弃了在上面发课程&#xff0c;再后来腾讯课堂就关闭了&#xff0c;以前发布的视频就没有地方发了&#xff0c;于是我…

Golang | Leetcode Golang题解之第485题最大连续1的个数

题目&#xff1a; 题解&#xff1a; func findMaxConsecutiveOnes(nums []int) (maxCnt int) {cnt : 0for _, v : range nums {if v 1 {cnt} else {maxCnt max(maxCnt, cnt)cnt 0}}maxCnt max(maxCnt, cnt)return }func max(a, b int) int {if a > b {return a}return …

QT--Qlabel学习、获取文本和设置文本、文本对齐方式、文本换行、显示图片

QLabel 是 Qt 中的标签类&#xff0c;通常用于显示提示性的文本&#xff0c;也可以显示图像 对齐方式 用于设置标签中的内容在水平和垂直两个方向上的对齐方式&#xff0c;比如左对齐、右对齐、上对齐、下对齐、水平居中、垂直居中等。 // 获取和设置文本的对齐方式 Qt::Ali…

第二代GPT-SoVITS V2:让声音克隆变得简单

随着人工智能技术的飞速发展&#xff0c;AI声音克隆已经成为一种趋势&#xff0c;广泛应用于各个领域。为了满足更多用户的需求&#xff0c;第二代GPT-SoVITS V2应运而生&#xff0c;它由RVC变声器创始人“花儿不哭”与AI音色转换技术Sovits开发者Rcell联合开发&#xff0c;是一…

有关 C#多表查询学习

导言 在后端多表查询这一块还是不太会&#xff0c;主要是在左连接和innerjoin这块&#xff0c;上课混的时间总是要还回来的...主要是举后端的几个案例来相应学习查询的知识。所用到的例子是自己搞的C#后端&#xff0c;数据库用的是若依的表&#xff0c;有些有些微改变。 多表查…

为什么SSH协议是安全的?

SSH的传输层协议&#xff08;Transport Layer Protocol&#xff09;和用户鉴权协议&#xff08;Authentication Protocol&#xff09;确保数据的传输安全&#xff0c;这里只介绍传输层协议&#xff0c;是SSH协议的基础。 本文针对SSH2协议。 1、客户端连接服务器 服务器默认…

相似扇形问题

甘肃临夏砖雕是一种历史悠久的古建筑装饰艺术&#xff0c;是第一批国家级非物质文化遗产,如图1是一块扇面形的临夏砖雕作品&#xff0c;它的部分设计图如图2&#xff0c;其中扇形OBC和扇形OAD有相同的圆心O&#xff0c;且圆心角O100度&#xff0c;若OA120cm, OB60cm &#xff0…

9.22前缀和

当我们计算n个数的和的时候&#xff0c;往往会采用循环操作&#xff0c;但是当我们要多次进行询问n个数之和时&#xff0c;如果采用多次循环&#xff0c;时间复杂度会升高&#xff0c;所以我们采用前缀和来解决多次询问时的求和 1.一维前缀和 提公因式&#xff0c;用分配律&am…

2024 kali系统2024版本,可视化界面汉化教程(需要命令行更改),英文版切换为中文版,基于Debian创建的kali虚拟机

我的界面如下所示 1. 安装 locales sudo apt install locales 2. 生成中文语言环境 sudo locale-gen zh_CN.UTF-8 如果你希望安装繁体中文&#xff0c;可以加入&#xff1a; sudo locale-gen zh_TW.UTF-8 3. 修改 /etc/default/locale 文件 确保有以下内容 LANGzh_CN.UT…

【优选算法】——双指针(下篇)!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~ &#x1f525;系列专栏&#xff1a;C刷题算法总结 &#x1f516;克心守己&#xff0c;律己则安 目录 1、有效三角形的个数 2、查找总价值为目标值的两个商品 3、三数之和 4、四数之和 5、完结散花 1、有…

react18中实现简易增删改查useReducer搭配useContext的高级用法

useReducer和useContext前面有单独介绍过&#xff0c;上手不难&#xff0c;现在我们把这两个api结合起来使用&#xff0c;该怎么用&#xff1f;还是结合之前的简易增删改查的demo&#xff0c;熟悉vue的应该可以看出&#xff0c;useReducer类似于vuex&#xff0c;useContext类似…

智慧供排水管网在线监测为城市安全保驾护航

一、方案背景 随着城市化进程的不断推进&#xff0c;城市供排水管网作为城市基础设施的关键组成部分&#xff0c;其安全稳定的运行对于确保城市居民的日常生活、工业生产活动以及整个生态环境的健康具有至关重要的作用。近年来&#xff0c;由于各种原因&#xff0c;城市供排水管…