【Gin框架深度解析】路由实现原理,让你彻底掌握Gin中路由的奥秘!

news2024/11/16 21:52:08

文章目录

  • Gin路由
    • 1、基本路由
    • 2、Restful风格的API
    • 3、API参数
    • 4、URL参数
    • 5、表单参数
    • 6、上传单个文件
      • 6.1、上传特定文件
    • 7、上传多个文件
    • 8、路由分组
    • 9、404页面处理
    • 10、路由原理

Gin路由

1、基本路由

​ 举一个例子:

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "hello word")
    })
    r.POST("/xxxpost",getting)
    r.PUT("/xxxput")
    //监听端口默认为8080
    r.Run(":8000")
}

//----------------解析-------------------//
	这里我们不做过多解释整个代码,在Gin简介中就有包含对代码的解释,主要是来说明下:r.POST()和r.PUT()方法。r.POST()和r.PUT()都是路由函数,用于绑定指定的HTTP请求方法(POST和PUT)和对应的处理函数。

如r.POST()用于绑定HTTP的POST请求,r.PUT()用于绑定HTTP的PUT请求。这两个函数的第一个参数是请求路径,第二个参数是处理该请求的函数。例如,在你的代码中,r.POST("/xxxpost", getting)表示将HTTP的POST请求与名为getting的函数绑定到/xxxpost路径上。

这样,在客户端发起POST请求到/xxxpost路径时,服务器将会调用名为getting的处理函数来处理该请求。同理,当客户端发起PUT请求到指定的路径时,服务器将会调用相应的处理函数来处理请求。

2、Restful风格的API

​ gin是支持restful风格的api(Representational State Transfer)-> 表现层状态转化,这是互联网应用程序的API设计理念:URL定位资源,用HTTP描述操作

1.获取文章 /blog/getXxx Get blog/Xxx

2.添加文章 /blog/addXxx POST blog/Xxx

3.修改文章 /blog/updateXxx PUT blog/Xxx

4.删除文章 /blog/delXxxx DELETE blog/Xxx

//----------------解析-------------------//
这段描述是一个 RESTful API 中对博客文章的四个基本操作的接口规范,其中 GET、POST、PUT 和 DELETE 都是 HTTP 协议中的请求方法,分别表示获取资源、新增资源、修改资源和删除资源。具体对应到博客文章上的操作可以描述如下:

获取文章:通过 GET 请求获取指定博客文章的内容,如 /blog/getXxx 可以获取 ID 为 Xxx 的博客文章的详细内容。

添加文章:通过 POST 请求向服务器提交一篇新的博客文章内容,如 /blog/addXxx 可以将新的博客文章添加到服务器上,并返回添加后的文章的信息。

修改文章:通过 PUT 请求更新指定博客文章的内容,如 /blog/updateXxx 可以更新 ID 为 Xxx 的博客文章的信息,可以修改博客文章的标题、内容、标签等属性。

删除文章:通过 DELETE 请求删除指定博客文章,如 /blog/delXxx 可以删除 ID 为 Xxx 的博客文章。在实际应用中,为了避免误删,通常会要求用户再次确认删除操作。

3、API参数

1、可以通过Context的Param方法来获取API参数

2、localhost:8000/xxx/zhangsan

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
)

func main() {
	r := gin.Default()
	r.GET("/user/:name/*action", func(c *gin.Context) {
		name := c.Param("name")
		action := c.Param("action")
		// 截取
		action = strings.Trim(action, "/")
		c.String(http.StatusOK, name+" is "+action)
	})

	// 默认监听端口为8080
	r.Run(":8000")
}

//----------------解析-------------------//
这里需要注意几个点:
1:name 和 *action -> 在gin框架中,使用冒号(:)来定义路径参数,使用星号(*)来定义匹配路径参数中斜杠(/)的通配符。例如,:name可以匹配任意非斜杠的字符,而*action可以匹配任意字符串,包括斜杠。这些符号不是固定写法,但是是gin框架中的约定俗成的写法。
2string.Trim方法:是 Go 语言中一个字符串处理的函数,用于去除字符串中开头和结尾的指定字符,返回处理后的字符串。函数签名为:Trim(s string, cutset string) string。其中 s 代表需要处理的字符串,cutset 代表需要去除的字符集合。在这段代码中,strings.Trim(action, "/"),表示除去action头尾的`/`

3、输出结果

4、URL参数

​ 有了API参数,当然也有URL参数,其中URL参数是通过DefaultQuery()或Query()方法获取的

  • 1)DefaultQuery()若参数不存在,则返回默认值;2)Query()若不存在,则返回空串。
  • API?name=xxx
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	r := gin.Default()
	r.GET("/user", func(c *gin.Context) {
		// 制定默认值
		// http://localhost:8080/user 才会打印出默认的值
		name := c.DefaultQuery("name", "访问到初始路径,返回默认值!")
		c.String(http.StatusOK, fmt.Sprintf("hello %s", name))
	})
	r.Run(":8000")
}

1、返回默认值

2、返回非默认值

5、表单参数

​ 表单传输为post请求,http常见的传输格式为4中:

  • application/json
  • application/x-www-form-urlencoded
  • application/xml
  • multipart/form-data

1、代码

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	r := gin.Default()
	r.POST("/form", func(c *gin.Context) {
		types := c.DefaultPostForm("type", "post")
		username := c.PostForm("username")
		password := c.PostForm("userpassword")
		c.String(http.StatusOK, fmt.Sprintf("username : %s, password : %s, type : %s", username, password, types))
	})
	r.Run()
}

//----------------解析-------------------//
这段代码创建了一个基于gin框架的Web服务器,当收到一个POST请求时,解析请求中的表单参数,并返回包含这些参数的字符串。

具体地说,这个Web服务器会监听地址为:8080的HTTP请求。当收到一个POST请求时,会调用回调函数func(c *gin.Context),在其中通过c.DefaultPostForm和c.PostForm获取请求中的表单参数。其中,c.DefaultPostForm可以获取表单参数中的指定参数,如果该参数不存在,则使用指定的默认值。而c.PostForm可以获取表单参数中的指定参数,如果该参数不存在则返回空字符串。最后,服务器会返回一个字符串,其中包含了解析到的表单参数的信息。

2、输出结果

6、上传单个文件

​ multipart/form-data格式用于文件的上传;gin文件上传与原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中

1、html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
          上传文件:<input type="file" name="file" >
          <input type="submit" value="提交">
    </form>
</body>
</html>

2、go文件

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    //限制上传最大尺寸
    r.MaxMultipartMemory = 8 << 20
    r.POST("/upload", func(c *gin.Context) {
        file, err := c.FormFile("file")
        if err != nil {
            c.String(500, "上传图片出错")
        }
        // c.JSON(200, gin.H{"message": file.Header.Context})
        c.SaveUploadedFile(file, file.Filename)
        c.String(http.StatusOK, file.Filename)
    })
    r.Run()
}

3、效果演示

6.1、上传特定文件

​ 有时候用户文件上传的时候需要指定文件的类型或者上传文件的大小,但是gin框架暂时没有提供这些函数,因此基于原生的函数写法自己创造一个可以限制文件大小及类型的函数。

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.POST("/upload", func(c *gin.Context) {
        _, headers, err := c.Request.FormFile("file")
        if err != nil {
            log.Printf("Error when try to get file: %v", err)
        }
        //headers.Size 获取文件大小
        if headers.Size > 1024*1024*2 {
            fmt.Println("文件太大了")
            return
        }
        //headers.Header.Get("Content-Type")获取上传文件的类型
        if headers.Header.Get("Content-Type") != "image/png" {
            fmt.Println("只允许上传png图片")
            return
        }
        c.SaveUploadedFile(headers, "./video/"+headers.Filename)
        c.String(http.StatusOK, headers.Filename)
    })
    r.Run()
}

//----------------解析-------------------//
这段代码使用 Gin 框架实现了一个简单的文件上传功能。在这个程序中,我们使用了 POST 请求来上传文件,URL 为 "/upload"。

在路由处理函数中,通过 c.Request.FormFile 方法获取文件对象,文件对象类型为 *multipart.FileHeader。在获取到文件对象之后,我们可以使用 FileHeader.Size 属性获取文件大小,使用 FileHeader.Header.Get("Content-Type") 获取文件类型。在这个程序中,我们限制上传文件的大小不能超过 2MB,且只允许上传 png 图片。

当文件通过验证后,使用 c.SaveUploadedFile 方法将文件保存在本地。最后,使用 c.String 方法返回上传文件的文件名。

需要注意的是,在程序运行之前,需要先确保项目目录下存在 video 目录。

7、上传多个文件

1、html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8000/upload" method="post" enctype="multipart/form-data">
          上传文件:<input type="file" name="files" multiple>
          <input type="submit" value="提交">
    </form>
</body>
</html>

2、go文件

package main

import (
   "github.com/gin-gonic/gin"
   "net/http"
   "fmt"
)

// gin的helloWorld

func main() {
   // 1.创建路由
   // 默认使用了2个中间件Logger(), Recovery()
   r := gin.Default()
   // 限制表单上传大小 8MB,默认为32MB
   r.MaxMultipartMemory = 8 << 20
   r.POST("/upload", func(c *gin.Context) {
      form, err := c.MultipartForm()
      if err != nil {
         c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
      }
      // 获取所有图片
      files := form.File["files"]
      // 遍历所有图片
      for _, file := range files {
         // 逐个存
         if err := c.SaveUploadedFile(file, file.Filename); err != nil {
            c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
            return
         }
      }
      c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
   })
   //默认端口号是8080
   r.Run(":8000")
}

8、路由分组

​ 路由分组(router groups)是为了管理一些相同的url

package main

import (
   "github.com/gin-gonic/gin"
   "fmt"
)

// gin的helloWorld

func main() {
   // 1.创建路由
   // 默认使用了2个中间件Logger(), Recovery()
   r := gin.Default()
   // 路由组1 ,处理GET请求
   v1 := r.Group("/v1")
   // {} 是书写规范
   {
      v1.GET("/login", login)
      v1.GET("submit", submit)
   }
   v2 := r.Group("/v2")
   {
      v2.POST("/login", login)
      v2.POST("/submit", submit)
   }
   r.Run(":8000")
}

func login(c *gin.Context) {
   name := c.DefaultQuery("name", "jack")
   c.String(200, fmt.Sprintf("hello %s\n", name))
}

func submit(c *gin.Context) {
   name := c.DefaultQuery("name", "lily")
   c.String(200, fmt.Sprintf("hello %s\n", name))
}

//----------------解析-------------------//
这是一个使用 Gin 框架创建的 Web 应用,包含了两个路由组,分别处理 GET 和 POST 请求。

路由组通过 r.Group 方法创建,并可以添加相同路径的不同 HTTP 方法的路由。比如,这里的 /login 路由在 v1 路由组中是 GET 请求,在 v2 路由组中是 POST 请求。

在 login 和 submit 处理函数中,使用 c.DefaultQuery 获取 URL 中的查询参数,如果不存在,则使用默认值。然后,使用 c.String 方法将字符串返回给客户端。

最后,通过 r.Run 方法运行应用,默认监听在 8000 端口。

9、404页面处理

package main

import (
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/user", func(c *gin.Context) {
        //指定默认值
        //http://localhost:8080/user 才会打印出来默认的值
        name := c.DefaultQuery("name", "Gopher陈")
        c.String(http.StatusOK, fmt.Sprintf("hello %s", name))2020-08-05 09:22:11 星期三
    })
    r.NoRoute(func(c *gin.Context) {
        c.String(http.StatusNotFound, "404 not found333333")
    })
    r.Run()
}

//----------------解析-------------------//
这段代码创建了一个名为 r 的 Gin 路由器,监听 /user 路径的 GET 请求,并将查询参数 name 的值打印出来。如果请求中没有提供 name 参数,则使用默认值 "Gopher陈"。此外,它还定义了一个 NoRoute 处理函数,用于处理所有未被定义的路由。如果请求的路径不匹配任何已定义的路由,则返回 404 not found333333。

当访问 http://localhost:8080/user 时,如果没有提供 name 参数,则返回 "hello Gopher陈"。如果提供了 name 参数,则返回 "hello " + name 的值。当访问除 /user 外的任何其他路径时,将返回 404 not found333333。

10、路由原理

Gin中的路由原理是基于HTTP请求方法和请求路径的匹配,当请求到来时,Gin会遍历已注册的路由,找到匹配的路由并执行相应的处理函数。

具体来说,当我们使用Gin注册路由时,可以通过gin.EngineGETPOSTPUTDELETE等方法来注册对应请求方法的路由,如:

r := gin.Default()

r.GET("/hello", func(c *gin.Context) {
    c.String(http.StatusOK, "Hello World")
})

这里注册了一个GET请求方法的路由,当请求路径为/hello时,会执行传入的匿名函数,返回"Hello World"字符串。

在路由的注册过程中,我们还可以使用参数来匹配请求路径,例如:

r.GET("/hello/:name", func(c *gin.Context) {
    name := c.Param("name")
    c.String(http.StatusOK, "Hello %s", name)
})

这里注册了一个GET请求方法的路由,使用:name参数匹配请求路径,当请求路径为/hello/xxx时,会执行传入的匿名函数,返回"Hello xxx"字符串。

总之,Gin的路由原理是根据请求方法和请求路径的匹配来执行相应的处理函数,使我们可以方便地实现RESTful API服务。

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

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

相关文章

ARM嵌入式编译器控制诊断信息(warning/error)

ARM编译器以警告&#xff08;warning&#xff09;和错误&#xff08;error&#xff09;的形式来提供编译诊断信息&#xff0c;并且用户可以通过一些命令行选项&#xff0c;来控制这些warnings和errors的打开或者关闭。编译器会在程序编译和链接过程中将遇到的warnings和errors在…

开关电源基础03:正激和反激开关电源拓扑(1)-正激拓扑

说在开头&#xff1a;关于薛定谔的波动方程&#xff08;2&#xff09; 全新的量子理论诞生不到一年&#xff0c;很快面临着粒子和波动的内战。矩阵力学从直接观测到的原子谱线出发&#xff0c;引入矩阵的数学工具&#xff0c;建立了整个新力学的大厦&#xff1b;它强调观测到的…

大数据Doris(十三):Duplicate数据模型以及聚合模型的局限性

文章目录 Duplicate数据模型以及聚合模型的局限性 一、Duplicate数据模型 二、聚合模型的局限性 Duplicate数据模型以及聚合模型的局限性 一、Duplicate数据模型 在某些多维分析场景下&#xff0c;数据既没有主键&#xff0c;也没有聚合需求&#xff0c;只需要将数据原封不…

JDK17新特性之--新的Compact Strings(JEP 254)

前言 JDK9将String底层的数据结构从private final char value[];改成了private final byte[] value; &#xff0c; JEP 254: Compact Strings(紧凑字符串)&#xff0c;这要修改的目的就是为了节省空间1。我们先看一下JDK9和JDK8中String源码的变化。 JDK9中String源码&#xf…

深度学习技巧应用12-神经网络训练中批归一化的应用

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用12-神经网络训练中批归一化的应用,在深度学习中,批归一化(Batch Normalization,简称BN)是一种重要的技巧,它在许多神经网络中都得到了广泛应用。本文将详细介绍批归一化的原理和应用,并结合PyTorch框架构建一个简…

法规标准-SAE J2802标准解读

SAE J2802是做什么的&#xff1f; SAE J2802全名为盲点监测系统&#xff08;BSMS&#xff09;&#xff1a;工作特性和用户界面&#xff0c;其中主要是对BSMS系统的工作特性及用户界面进行了介绍 BSMS目标 强制性目标 任何可获得公路许可的车辆&#xff0c;此处视为大于125 …

深入浅出二叉树— C语言版【数据结构】

目录 ​编辑 1.树概念及结构 1.1树的概念 1.2 树的相关概念 ​1.3 树的表示 2.二叉树概念及结构 2.1概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 简单二叉树题目练习 2.5 二叉树的存储结构 2.5.1 顺序存储——堆 2.5.2 链式存储 1.树概念及结构 1.1树的概念 树…

Java --- String类

&#xff08;一&#xff09;String java.lang.String 类代表字符串。Java 程序中所有的字符串文字&#xff08;例如 "hello" &#xff09;都可以看作是实现此类的实例。 字符串是常量&#xff0c;用双引号引起来表示。它们的值在创建之后不能更改。 字符串 St…

深度卷积图神经网络(Deep Convolutional Graph Neural Network,DCGNN)的基本概念与应用

目录 一、引言 1.1 神经网络的发展历程 1.2 图神经网络的出现 二、深度卷积图神经网络的基本概念 2.1 图的表示 2.2 图卷积神经网络 2.3 深度卷积图神经网络 三、深度卷积图神经网络的应用 3.1 图像分类 3.2 图像分割 3.3 图像生成 四、深度卷积图神经网络的优缺点 …

【数据结构与算法】图的概述(内含源码)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️数据结构与算法】 学习名言&#xff1a;天子重英豪&#xff0c;文章教儿曹。万般皆下品&#xff0c;惟有读书高——《神童诗劝学》 系列文章目录 第一章 ❤️ 学前知识 第二章 ❤️ 单向链表 第三章…

分布式一致性Hash算法原理及实现

文章目录 一致性Hash原理提高容错性和和扩展性一致性Hash实现思路代码 一致性Hash原理 简单来说&#xff0c;一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环&#xff0c; 如假设某哈希函数 H 的值空间为 0 ~ 2^32-1&#xff08;即哈希值是一个32位无符号整形&#xff09;…

搜狗百科怎么创建?搜狗百科创建指南(经验分享)

搜狗百科是一个允许用户创建、编辑和维护百科全书的网站。它是搜狗搜索旗下的一个产品&#xff0c;为用户提供了一个共享知识的平台。创建一个搜狗百科词条并非难事&#xff0c;但需要遵守一些注意事项。 话不多说。小媒同学将介绍搜狗百科词条的创建过程和注意事项。 一、创建…

java基础入门-04-【集合学生管理系统】

Java基础入门-04-【集合&学生管理系统】 11、集合&学生管理系统11.1.ArrayList集合和数组的优势对比&#xff1a;11.1.1 ArrayList类概述11.1.2 ArrayList类常用方法11.1.2.1 构造方法11.1.2.2 成员方法11.1.2.3 示例代码 11.1.3 ArrayList存储字符串并遍历11.1.3.1 案…

【观察】甲骨文以“双引擎”驱动,加速中国企业拥抱决策智能

毫无疑问&#xff0c;当前中国整体经济形态正在从传统经济向数字经济转型&#xff0c;千行百业也在加速数字化转型&#xff0c;特别是随着企业数据的沉淀越来越庞大&#xff0c;对数据平台以及智能决策等新技术的需求也越来越旺盛。 国家发布的《“十四五”数字经济发展规划》中…

视频里的音乐怎么转换成mp3格式?

视频里的音乐怎么转换成mp3格式&#xff1f;视频里的音乐转换为mp3的原因有很多&#xff0c;主要是因为mp3格式是一种音频格式&#xff0c;文件大小较小&#xff0c;更易于存储和传输。相比之下&#xff0c;视频格式则是一种视频文件格式&#xff0c;虽然包含音频&#xff0c;但…

Q-in-Q 和 MAC-in-MAC

例题引入&#xff1a; 1. 城域以太网在各个用户以太网之间建立多点第二层连接&#xff0c;IEEE802.1ad定义运营商网桥协议提供的基本技术是在以太网帧中插入&#xff08;26&#xff09;字段&#xff0c;这种技术被称为&#xff08;27&#xff09;技术。 (26)A.运营商VLAN标记…

Hive知识点的回顾

一、Hive的序列化和反序列化 Hive读取文件机制&#xff1a;读取文件中的每一行 > 反序列化 > 通过分隔符进行切割&#xff0c;返回数据表中的每一行对象。 Hive写文件机制&#xff1a;把数据表中的每一行Row对象 > 调用LazySimpleSerde类中的序列化方法 > 把Row对象…

基于AT89C51单片机的电子秒表设计与仿真

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/87759735?spm1001.2014.3001.5503 源码获取 主要内容&#xff1a; 设计一个电子钟,实现对时、分、秒的显示的控制,电路采用24小时计时方式。另一个功能是秒表功能…

JVM内存模型和结构介绍

什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM是一个虚构出来的计算机&#xff0c;有着自己完善的硬件架构&#xff0c;如处理器、堆栈等。 为什么需要JVM&#xff1f; Java语言使用Java虚拟机屏蔽了与具体平台相关的信息&…

执行网格中有特定数量节点的传感器网络部署(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 ​无线传感器网络是通过大量分布的传感器节点作为终端来协同感知和自主地监测外部世界,以多跳、自组织或协作的方式进行通信和…