hincky的主页 hincky的主页
  • 学习笔记

    • Vue笔记
    • Vuepress
    • nginx
  • 语言类

    • java
    • go
    • python
    • 设计模式
  • 框架类

    • Spring
    • Spring Security
    • Mybatis
  • 容器技术

    • docker
    • k8s
    • helm
    • prometheus
    • grafana
    • jenkins
  • 命令集合

    • linux命令
    • docker命令
    • git命令
    • vim命令
    • k8s命令
  • 数据库

    • sql
    • mysql
  • 协议

    • 网络模型
    • http/1.1
    • WebSocket
    • http/2
    • TLS/SSL
    • tcp
    • IP
    • tcpdump抓包命令
    • wireshark抓包工具
  • 通用

    • Git
  • 技术分享

    • git push/pull总是超时怎么办
    • idea debug技巧
    • postman使用
    • 问题总结
    • idea使用技巧
  • Oauth2

    • Oauth2原理
  • 项目列表

    • redis项目
    • 微服务项目
  • 分类
  • 标签
  • 归档
  • 随笔
GitHub (opens new window)

Hincky

当有趣的人,做想做的事
  • 学习笔记

    • Vue笔记
    • Vuepress
    • nginx
  • 语言类

    • java
    • go
    • python
    • 设计模式
  • 框架类

    • Spring
    • Spring Security
    • Mybatis
  • 容器技术

    • docker
    • k8s
    • helm
    • prometheus
    • grafana
    • jenkins
  • 命令集合

    • linux命令
    • docker命令
    • git命令
    • vim命令
    • k8s命令
  • 数据库

    • sql
    • mysql
  • 协议

    • 网络模型
    • http/1.1
    • WebSocket
    • http/2
    • TLS/SSL
    • tcp
    • IP
    • tcpdump抓包命令
    • wireshark抓包工具
  • 通用

    • Git
  • 技术分享

    • git push/pull总是超时怎么办
    • idea debug技巧
    • postman使用
    • 问题总结
    • idea使用技巧
  • Oauth2

    • Oauth2原理
  • 项目列表

    • redis项目
    • 微服务项目
  • 分类
  • 标签
  • 归档
  • 随笔
GitHub (opens new window)
  • java

  • python

  • Spring

  • SpringMVC

  • SpringSecurity

  • Mybatis

  • 设计模式

  • Go

    • 基础语法

    • Gin框架

      • 框架安装
        • 概述
        • Gin 安装
      • 路由配置
        • 概述
        • 路由配置
        • 源码
      • 日志记录
        • 概述
        • 日志格式
        • Logrus 使用
        • 源码
      • 数据绑定和验证
        • 概述
        • 源码
      • 自定义错误处理
        • 概述
        • 错误处理
        • 自定义错误处理
        • panic 和 recover
        • 源码
      • 统一定义 API 错误码
        • 改之前
        • 改之后
        • errno 包源码
        • 错误码规则
          • 错误码为 5 位数
    • Go gRPC

    • go-gin-api [文档]

    • go基本介绍
      • 安装go
      • hello world
      • 变量类型
      • 变量和声明
        • 定义和赋值分开
        • 定义和赋值合并
        • 最简单的写法
        • 最简写法结合函数
        • 多个变量同时赋值
        • 变量总结
      • if
      • 导入包
      • 运行go代码
      • 函数声明
        • 返回值个数
        • 参数接收
        • 两个参数都接收
        • 只接收其中一个参数
    • Go结构体
      • 定义结构体
      • 声明和初始化
        • 结构体字段
        • 结构体初始化
        • 函数参数传递方式
        • 镜像复制
        • 指针
      • 结构体上的函数
      • 构造器
        • new
    • Go相关项目推荐
      • 收录golang的一些好的开源项目
  • 后端
  • Go
  • Gin框架
hincky
2022-11-21
目录

路由配置

# 概述

这篇文章分享 Gin 的路由配置,主要包含的功能点如下:

  • 实现了,路由分组 v1版本、v2版本。
  • 实现了,生成签名和验证验证。
  • 实现了,在配置文件中读取配置。

# 路由配置

比如我们的接口地址是这样的:

  • /v1/product/add
  • /v1/member/add
  • /v2/product/add
  • /v2/member/add

假设需求是这样的,接口支持多种请求方式,v1 不需签名验证,v2 需要签名验证,路由文件应该这样写:

package router

import (
	"ginDemo/common"
	"ginDemo/controller/v1"
	"ginDemo/controller/v2"
	"github.com/gin-gonic/gin"
	"net/url"
	"strconv"
)

func InitRouter(r *gin.Engine)  {

	r.GET("/sn", SignDemo)

	// v1 版本
	GroupV1 := r.Group("/v1")
	{
		GroupV1.Any("/product/add", v1.AddProduct)
		GroupV1.Any("/member/add", v1.AddMember)
	}

	// v2 版本
	GroupV2 := r.Group("/v2", common.VerifySign)
	{
		GroupV2.Any("/product/add", v2.AddProduct)
		GroupV2.Any("/member/add", v2.AddMember)
	}
}

func SignDemo(c *gin.Context) {
	ts := strconv.FormatInt(common.GetTimeUnix(), 10)
	res := map[string]interface{}{}
	params := url.Values{
		"name"  : []string{"a"},
		"price" : []string{"10"},
		"ts"    : []string{ts},
	}
	res["sn"] = common.CreateSign(params)
	res["ts"] = ts
	common.RetJson("200", "", res, c)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

.Any 表示支持多种请求方式。

controller/v1 表示 v1 版本的文件。

controller/v2 表示 v2 版本的文件。

SignDemo 表示生成签名的Demo。

接下来,给出一些代码片段:

验证签名方法:

// 验证签名
func VerifySign(c *gin.Context) {
	var method = c.Request.Method
	var ts int64
	var sn string
	var req url.Values

	if method == "GET" {
		req = c.Request.URL.Query()
		sn = c.Query("sn")
		ts, _  = strconv.ParseInt(c.Query("ts"), 10, 64)

	} else if method == "POST" {
		req = c.Request.PostForm
		sn = c.PostForm("sn")
		ts, _  = strconv.ParseInt(c.PostForm("ts"), 10, 64)
	} else {
		RetJson("500", "Illegal requests", "", c)
		return
	}

	exp, _ := strconv.ParseInt(config.API_EXPIRY, 10, 64)

	// 验证过期时间
	if ts > GetTimeUnix() || GetTimeUnix() - ts >= exp {
		RetJson("500", "Ts Error", "", c)
		return
	}

	// 验证签名
	if sn == "" || sn != CreateSign(req) {
		RetJson("500", "Sn Error", "", c)
		return
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

生成签名的方法:

// 生成签名
func CreateSign(params url.Values) string {
	var key []string
	var str = ""
	for k := range params {
		if k != "sn" {
			key = append(key, k)
		}
	}
	sort.Strings(key)
	for i := 0; i < len(key); i++ {
		if i == 0 {
			str = fmt.Sprintf("%v=%v", key[i], params.Get(key[i]))
		} else {
			str = str + fmt.Sprintf("&%v=%v", key[i], params.Get(key[i]))
		}
	}
	// 自定义签名算法
	sign := MD5(MD5(str) + MD5(config.APP_NAME + config.APP_SECRET))
	return sign
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

获取参数的方法:

// 获取 Get 参数
name := c.Query("name")
price := c.DefaultQuery("price", "100")

// 获取 Post 参数
name := c.PostForm("name")
price := c.DefaultPostForm("price", "100")

// 获取 Get 所有参数
ReqGet = c.Request.URL.Query()

//获取 Post 所有参数
ReqPost = c.Request.PostForm
1
2
3
4
5
6
7
8
9
10
11
12
13

v1 业务代码:

package v1

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

func AddProduct(c *gin.Context)  {
	// 获取 Get 参数
	name  := c.Query("name")
	price := c.DefaultQuery("price", "100")

	c.JSON(200, gin.H{
		"v1"    : "AddProduct",
		"name"  : name,
		"price" : price,
	})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

v2 业务代码:

package v2

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

func AddProduct(c *gin.Context)  {
	// 获取 Get 参数
	name  := c.Query("name")
	price := c.DefaultQuery("price", "100")

	c.JSON(200, gin.H{
		"v1"    : "AddProduct",
		"name"  : name,
		"price" : price,
	})
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

接下来,直接看效果吧。

访问 v1 接口:

访问后,直接返回数据,不走签名验证。

访问 v2 接口:

进入了这段验证:

// 验证过期时间
if ts > GetTimeUnix() || GetTimeUnix() - ts >= exp {
	RetJson("500", "Ts Error", "", c)
	return
}
1
2
3
4
5

修改为合法的时间戳后:

进入了这段验证:

// 验证签名
if sn == "" || sn != CreateSign(req) {
	RetJson("500", "Sn Error", "", c)
	return
}
1
2
3
4
5

修改为合法的签名后:

至此,简单的路由配置已经实现了。

对了,还有一个点没说,就是如何读取配置文件中的配置,我是这样做的:

package config

const (
	PORT       = ":8080"
	APP_NAME   = "ginDemo"
	APP_SECRET = "6YJSuc50uJ18zj45"
	API_EXPIRY = "120"
)
1
2
3
4
5
6
7
8

引入 config 包,直接 config.xx 即可。

# 源码

下载源码后,请先执行 dep ensure 下载依赖包!

查看源码 (opens new window)

编辑 (opens new window)
框架安装
日志记录

← 框架安装 日志记录→

最近更新
01
人生前期重要的能力
05-17
02
防火墙命令
04-11
03
docker-compose部署mysql主从集群
03-22
更多文章>
Theme by Vdoing | Copyright © 2022-2023 Hincky | MIT License | 粤ICP备2022120427号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式