Skip to content

Gin框架

请求

获取请求参数

go
package main

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

func main() {
	router := gin.Default()

	router.GET("/example", func(c *gin.Context) {
		// 使用c.Query()方法获取参数值
		paramValue := c.Query("paramName")

		// 使用c.DefaultQuery()方法获取参数值,如果参数不存在,设置默认值
		defaultParamValue := c.DefaultQuery("defaultParamName", "defaultValue")

		c.String(200, "ParamValue: %s; DefaultParamValue: %s", paramValue, defaultParamValue)
	})

	router.Run(":8080")
}

从uri中绑定参数到struct

MustBindShouldBind的区别:MustBind在失败后,会自动调用AbortWithError(400),代码无法再自定义返回错误,ShouldBind在绑定失败后不会设置响应,而是返回错误。如果希望手动管理响应,使用后者。

validator:Package validator

go
// Binding from JSON
type Login struct {
	User     string `form:"user" json:"user" xml:"user"  binding:"required"`
	Password string `form:"password" json:"password" xml:"password" binding:"required"`
}

func main() {
	router := gin.Default()

	// Example for binding JSON ({"user": "manu", "password": "123"})
	router.POST("/loginJSON", func(c *gin.Context) {
		var json Login
		if err := c.ShouldBindJSON(&json); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if json.User != "manu" || json.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	// Example for binding XML (
	//	<?xml version="1.0" encoding="UTF-8"?>
	//	<root>
	//		<user>manu</user>
	//		<password>123</password>
	//	</root>)
	router.POST("/loginXML", func(c *gin.Context) {
		var xml Login
		if err := c.ShouldBindXML(&xml); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if xml.User != "manu" || xml.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	// Example for binding a HTML form (user=manu&password=123)
	router.POST("/loginForm", func(c *gin.Context) {
		var form Login
		// This will infer what binder to use depending on the content-type header.
		if err := c.ShouldBind(&form); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if form.User != "manu" || form.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

	// Listen and serve on 0.0.0.0:8080
	router.Run(":8080")
}

获取请求URL

go
package main

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

func main() {
	router := gin.Default()

	router.GET("/example", func(c *gin.Context) {
		// 获取完整的URL
		fullURL := c.Request.URL.String()

		c.String(200, "Full URL: %s", fullURL)
	})

	router.Run(":8080")
}

获取请求body

在Go语言的Gin框架中,要将请求的body打印出来,你可以使用以下代码:

go
package main

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

func main() {
	r := gin.Default()

	r.POST("/", func(c *gin.Context) {
		// 读取请求的body
		bodyBytes, err := ioutil.ReadAll(c.Request.Body)
		if err != nil {
			c.String(400, "请求body读取错误: %v", err)
			return
		}

		// 打印请求的body
		fmt.Println(string(bodyBytes))

		// 将读取后的body重新写回
		c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))

		c.String(200, "请求body已打印")
	})

	r.Run(":8080")
}

这个例子中,我们创建了一个简单的Gin服务器,监听POST请求。在这个请求处理函数中,我们读取请求的body,将其转换为字符串并打印出来。然后,我们将读取后的body重新写回,以便其他中间件或处理函数可以继续使用它。

响应

如何把http.Response对象作为gin的响应

要将http.Response对象的内容作为Gin框架的响应,可以将http.Response对象的StatusCode、Header和Body分别设置为Gin上下文(*gin.Context)的响应状态码、响应头和响应体。

以下是一个例子:

go
package main

import (
	"io"
	"net/http"

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

func main() {
	router := gin.Default()

	router.GET("/proxy", func(c *gin.Context) {
		// 发送请求并获取http.Response对象
		response, err := http.Get("http://example.com")
		if err != nil {
			c.String(http.StatusInternalServerError, "Error making request: %v", err)
			return
		}
		defer response.Body.Close()

		// 将http.Response的状态码设置为Gin响应的状态码
		c.Status(response.StatusCode)

		// 将http.Response的Header设置为Gin响应的Header
		for key, values := range response.Header {
			for _, value := range values {
				c.Header(key, value)
			}
		}

		// 将http.Response的Body设置为Gin响应的Body
		io.Copy(c.Writer, response.Body)
	})

	router.Run(":8080")
}

在这个例子中,我们创建了一个Gin路由,当访问/proxy时,会发送一个请求到http://example.com,然后将收到的http.Response对象的内容作为Gin响应返回。

注意,我们使用io.Copy()函数将response.Body复制到Gin上下文的c.Writer中。这样可以避免一次性读取整个响应体到内存,特别是当响应体很大时,这种方式更加高效。

路由

把所有url都路由到一个handler上

go
outer := gin.Default()
outer.Any("/*any", func(c *gin.Context) {
  c.String(200, "All URLs are handled by this handler.")
)

实现反向代理

go
func main() {
	r := gin.Default()

	// 假设你的后端服务地址为:http://localhost:8081
	backendURL, err := url.Parse("http://localhost:8081")
	if err != nil {
		fmt.Println("Error parsing backend URL:", err)
		return
	}

	r.Any("/*path", func(c *gin.Context) {
		// 设置需要传递到后端服务的头部信息
		c.Request.Header.Set("X-Forwarded-Host", c.Request.Host)
		c.Request.Header.Set("X-Forwarded-Proto", c.Request.URL.Scheme)

		// 创建一个反向代理处理器
		proxy := httputil.NewSingleHostReverseProxy(backendURL)

		// 修改请求的URL,使其指向后端服务
		c.Request.URL.Path = c.Param("path")
		c.Request.URL.RawPath = ""
		c.Request.URL.RawQuery = ""

		// 通过反向代理处理器处理请求
		proxy.ServeHTTP(c.Writer, c.Request)
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	r.Run(":8080")
}