欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang中web參數(shù)校驗的實現(xiàn)

 更新時間:2025年11月02日 09:51:06   作者:Asakeiii  
本文介紹了使用Gin框架進行參數(shù)校驗的幾種方法,包括JSON、URL查詢、表單數(shù)據(jù)的校驗,常用校驗規(guī)則,自定義錯誤信息和自定義校驗規(guī)則,具有一定的參考價值,感興趣的可以了解一下

參數(shù)校驗

確保我們的應(yīng)用接收到的數(shù)據(jù)是格式正確并且安全的

基本用法

JSON

假設(shè)我們正在開發(fā)一個登錄接口,希望用戶必須提供用戶名和密碼。在 Gin 中,我們首先會定義一個 Go 的 struct 來描述這個數(shù)據(jù)結(jié)構(gòu)。

type Login struct {
	User     string `json:"user" binding:"required"`
	Password string `json:"password" binding:"required"`
}
  • json:“…” 標簽: 這個標簽告訴 Gin,當它解析傳入的 JSON 數(shù)據(jù)時,JSON 中的 user 字段應(yīng)該映射到我們結(jié)構(gòu)體中的 User 字段。
  • binding:“required” 標簽: 這是最核心的部分!binding 就是用來做數(shù)據(jù)校驗的。required 是一個校驗規(guī)則,意思是“這個字段是必填的,不能為空”。
func loginHandler(c *gin.Context) {
	var login Login

	// 嘗試將請求的 JSON body 綁定到 login 結(jié)構(gòu)體上
	// 在綁定的同時,Gin 會根據(jù) "binding" 標簽進行校驗
	err := c.ShouldBindJSON(&login)
	if err != nil {
		// 如果 err 不是 nil,說明校驗失敗了!
		// 比如,某個 "required" 的字段沒有被提供。
		// Gin 通常會自動返回一個 400 Bad Request 錯誤。
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	// 如果 err 是 nil,說明所有校驗都通過了!
	c.JSON(200, gin.H{"status": "you are logged in"})
}

URL

除了處理 JSON,我們經(jīng)常還需要處理來自 URL 查詢(Query)和 HTML 表單(Form)的數(shù)據(jù)。
Gin 的設(shè)計非常統(tǒng)一。我們的 struct 定義方式幾乎不變,只需要更換一個綁定方法就可以了。

如何校驗 URL 查詢參數(shù),比如這樣一個請求:GET /search?keyword=gin&page=1
我們希望 keyword 是必填的,并且 page 必須是一個大于 0 的數(shù)字。
首先,還是定義我們的 struct:

type SearchQuery struct {
	Keyword string `form:"keyword" binding:"required"`
	Page    int    `form:"page"    binding:"required,gt=0"`
}
  • 我們用了 form:“…” 標簽,而不是 json:“…”。這個 form 標簽既可以用于 URL 查詢參數(shù),也可以用于表單數(shù)據(jù)。
  • 我在 Page 字段的 binding 里加了一個新規(guī)則 gt=0,它的意思是 “greater than 0(必須大于0)。
func searchHandler(c *gin.Context) {
    var query SearchQuery

    // 從 URL query 中綁定并校驗參數(shù)
    // 注意這里換成了 ShouldBindQuery
    err := c.ShouldBindQuery(&query)

    if err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    // 校驗通過!
    c.JSON(200, gin.H{
        "message": "search parameters are valid",
        "keyword": query.Keyword,
        "page":    query.Page,
    })
}

常用的校驗規(guī)則

我們通過一個用戶注冊的例子來看看:

type RegisterUser struct {
	// 用戶名:必填,長度在 4 到 20 個字符之間
	Username string `json:"username" binding:"required,min=4,max=20"`

	// 郵箱:必填,且必須是合法的郵箱格式
	Email string `json:"email" binding:"required,email"`

	// 年齡:選填,但如果提供了,必須大于等于 18 歲,小于等于 100 歲
	Age int `json:"age" binding:"gte=18,lte=100"`

	// 用戶類型:必填,并且值必須是 'user' 或 'admin' 中的一個
	UserType string `json:"user_type" binding:"required,oneof=user admin"`
}
  • min=4,max=20:用于字符串、數(shù)組等,限制其最小和最大長度。多個規(guī)則用逗號 , 分隔。
  • email:檢查字符串是否符合標準的 email 格式。
  • gte=18:意思是 “Greater Than or Equal To”,即大于或等于 18。
  • lte=100:意思是 “Less Than or Equal To”,即小于或等于 100。
  • oneof=user admin:表示這個字段的值必須是后面列出的值之一(用空格分隔)。
func registerUserHandler(c *gin.Context) {
	var register RegisterUser
	err := c.ShouldBindJSON(&register)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	c.JSON(200, gin.H{
		"username": register.Username,
		"email":    register.Email,
	})
}

自定義錯誤信息

核心思路是:捕獲到校驗錯誤后,我們不再直接把它整個返回,而是逐一檢查是哪個字段的哪條規(guī)則出錯了,然后根據(jù)這些信息,手動“翻譯”成我們想展示的話。

func registerUserHandler(c *gin.Context) {
	var register RegisterUser
	err := c.ShouldBindJSON(&register)
	if err != nil {
		var verrs validator.ValidationErrors
		ok := errors.As(err, &verrs)
		if !ok {
			// 如果不是 ValidationErrors 類型的錯誤,直接返回原始錯誤
			c.JSON(400, gin.H{"error": err.Error()})
			return
		}
		// 創(chuàng)建一個 map 來存放我們“翻譯”后的錯誤信息
		// key 是字段名,value 是錯誤信息
		// 比如:{"Username": "長度不能小于 4 個字符"}
		translatedErrors := make(map[string]string)
		for _, fe := range verrs {
			// fe.Field() 獲取出錯的字段名,比如 "Username"
			translatedErrors[fe.Field()] = getErrorMsg(fe)
		}

		c.JSON(400, gin.H{"errors": translatedErrors})
		return
	}

	c.JSON(200, gin.H{
		"username": register.Username,
		"email":    register.Email,
	})
}

// 這個函數(shù)專門用來“翻譯”錯誤信息
func getErrorMsg(fe validator.FieldError) string {
	// fe.Tag() 能獲取到是哪個校驗規(guī)則出錯了,比如 "required", "min", "email"
	switch fe.Tag() {
	case "required":
		return "這是必填項"
	case "min":
		// fe.Param() 能獲取到規(guī)則后面的參數(shù),比如 "min=4" 中的 "4"
		return "長度不能小于 " + fe.Param() + " 個字符"
	case "max":
		return "長度不能超過 " + fe.Param() + " 個字符"
	case "email":
		return "請輸入正確的郵箱地址"
	case "oneof":
		return "必須是 " + fe.Param() + " 中的一個"
	default:
		return "未知錯誤"
	}
}

自定義校驗規(guī)則

當內(nèi)置的規(guī)則(像 required, email, min, max 等)不夠用時,我們就需要自定義規(guī)則。比如,我們想強制要求“密碼必須同時包含字母和數(shù)字”。

整個過程分為三步,我們一步一步來:

  1. 編寫一個自定義校驗函數(shù)
    這個函數(shù)需要一個特定的格式。它接收一個 validator.FieldLevel 類型的參數(shù),并返回一個 bool 值。返回 true 表示校驗通過,false 表示失敗。
// isPasswordStrong 就是我們的自定義校驗函數(shù)
func isPasswordStrong(fl validator.FieldLevel) bool {
    // fl.Field().String() 可以獲取到字段的字符串值
    password := fl.Field().String()
    
    hasLetter := false
    hasDigit := false

    // 遍歷密碼字符串,檢查是否同時包含字母和數(shù)字
    for _, char := range password {
        if unicode.IsLetter(char) {
            hasLetter = true
        }
        if unicode.IsDigit(char) {
            hasDigit = true
        }
    }
    
    return hasLetter && hasDigit
}
  1. 將自定義函數(shù)“注冊”到 Gin 的校驗器里
    光寫好函數(shù)還不行,我們得告訴 Gin 的校驗器:“嘿,我這里有一個新的校驗規(guī)則,它的名字叫 strong_password,對應(yīng)的處理函數(shù)是 isPasswordStrong。”

    這個注冊過程通常在你的程序啟動時(比如 main 函數(shù)里)完成。

// 從 Gin 的 binding 中獲取底層的 validator 引擎
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		// 注冊我們的自定義校驗函數(shù)
		// 第一個參數(shù)是這個規(guī)則在 struct tag 中使用的名字
		// 第二個參數(shù)是我們的函數(shù)
		v.RegisterValidation("strong_password", isPasswordStrong)
	}
  1. 在 Struct Tag 中使用新規(guī)則
    一旦注冊成功,我們就可以像使用任何內(nèi)置規(guī)則一樣,在 struct tag 中使用 strong_password 了。

到此這篇關(guān)于Golang中web參數(shù)校驗的實現(xiàn)的文章就介紹到這了,更多相關(guān)Golang web參數(shù)校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go?Java?算法之字符串解碼示例詳解

    Go?Java?算法之字符串解碼示例詳解

    這篇文章主要為大家介紹了Go?Java?算法之字符串解碼示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Golang處理內(nèi)存溢出方式

    Golang處理內(nèi)存溢出方式

    本文介紹了Golang中分析內(nèi)存溢出問題的三種工具:pprof、GoMemstats和程序crash時自動創(chuàng)建dump文件,通過這些工具,可以對程序的內(nèi)存使用情況進行詳細分析,從而找出內(nèi)存溢出的原因
    2024-12-12
  • Go語言對JSON數(shù)據(jù)進行序列化和反序列化

    Go語言對JSON數(shù)據(jù)進行序列化和反序列化

    這篇文章介紹了Go語言對JSON數(shù)據(jù)進行序列化和反序列化的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • 一文帶你掌握Go語言運算符的使用

    一文帶你掌握Go語言運算符的使用

    運算符用于在程序運行時執(zhí)行數(shù)學(xué)或邏輯運算。Go 語言內(nèi)置的運算符有:算術(shù)運算符、關(guān)系運算符、邏輯運算符、位運算符、賦值運算符、其他運算符。本文將帶大家詳細了解一下這些運算符的使用,感興趣的可以了解一下
    2022-04-04
  • go實現(xiàn)冒泡排序算法

    go實現(xiàn)冒泡排序算法

    冒泡排序算法是數(shù)據(jù)結(jié)構(gòu)中常用的一種算法,本文就介紹了go實現(xiàn)冒泡排序算法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Go語言共享內(nèi)存讀寫實例分析

    Go語言共享內(nèi)存讀寫實例分析

    這篇文章主要介紹了Go語言共享內(nèi)存讀寫方法,實例分析了共享內(nèi)存的原理與讀寫技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • Golang學(xué)習筆記(一):簡介

    Golang學(xué)習筆記(一):簡介

    這篇文章主要介紹了Golang學(xué)習筆記(一):簡介,本文講解了Go語言最主要的特性、安裝、環(huán)境變量設(shè)置、整體目錄結(jié)構(gòu)、Helloworld、go命令、調(diào)試、編輯器設(shè)置等內(nèi)容,需要的朋友可以參考下
    2015-05-05
  • golang http使用踩過的坑與應(yīng)對方式

    golang http使用踩過的坑與應(yīng)對方式

    這篇文章主要介紹了golang http使用踩過的坑與應(yīng)對方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 詳解如何在golang項目開發(fā)中創(chuàng)建自己的Module

    詳解如何在golang項目開發(fā)中創(chuàng)建自己的Module

    既然我們使用了很多開源的 module為我們的日常開發(fā)提供了很多的便捷性,那我們該如何實現(xiàn)自己的 module 來提供給團隊中使用,接下小編就給大家介紹一下在golang項目開發(fā)如何創(chuàng)建自己的Module,需要的朋友可以參考下
    2023-09-09
  • 淺析Go項目中的依賴包管理與Go?Module常規(guī)操作

    淺析Go項目中的依賴包管理與Go?Module常規(guī)操作

    這篇文章主要為大家詳細介紹了Go項目中的依賴包管理與Go?Module常規(guī)操作,文中的示例代碼講解詳細,對我們深入了解Go語言有一定的幫助,需要的可以跟隨小編一起學(xué)習一下
    2023-10-10

最新評論