Golang中gin.Negotiate的示例代码

Golang中gin.Negotiate的示例代码 如果有人能发布一个示例,解释如何根据请求的 Accept 头部返回不同格式的响应,那将非常有帮助。

我搜索了很长时间,找不到任何关于如何根据 Accept 头部实际渲染响应的示例。 而且肯定没有关于如何根据包含 API 版本号的自定义媒体类型(如 “application/vnd.health.json;version=1.0.0” 或 “application/vnd.kliket.health+v1.json”)进行渲染的示例。

以下是我目前所了解到的内容:

func Health(c *gin.Context) {
	startupTime := c.MustGet("startupTime").(time.Time)
	status := models.NewHealth(startupTime)
	c.Negotiate(http.StatusOK, gin.Negotiate{
		Offered:  []string{"application/vnd.health.json;version=1.0.0", gin.MIMEJSON, gin.MIMEYAML, gin.MIMEXML, gin.MIMEHTML},
		HTMLName: "",
		HTMLData: status,
		JSONData: status,
		XMLData:  status,
		YAMLData: status,
		Data:     status,
	})
}

我可以获取除 HTML 和我自定义的版本化媒体类型(这是首选类型)之外的所有格式。

我找不到任何关于 HTMLName 应该填入什么内容,或者如何为我的自定义媒体类型注册 Render 的示例。


更多关于Golang中gin.Negotiate的示例代码的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中gin.Negotiate的示例代码的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


以下是使用 gin.Negotiate 根据 Accept 头部返回不同格式响应的完整示例,包括自定义媒体类型的处理:

package main

import (
	"net/http"
	"time"

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

type Health struct {
	Status    string    `json:"status" xml:"status" yaml:"status"`
	Startup   time.Time `json:"startup" xml:"startup" yaml:"startup"`
	Timestamp time.Time `json:"timestamp" xml:"timestamp" yaml:"timestamp"`
}

// 自定义渲染器
type CustomRenderer struct {
	Version string
	Data    interface{}
}

func (r CustomRenderer) Render(w http.ResponseWriter) error {
	// 这里实现自定义格式的渲染逻辑
	// 例如:根据版本号返回不同的JSON结构
	return nil
}

func (r CustomRenderer) WriteContentType(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/vnd.health.json;version="+r.Version)
}

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

	// 注册自定义渲染器
	gin.MIME("application/vnd.health.json;version=1.0.0", []string{".v1json"})
	gin.MIME("application/vnd.health.json;version=2.0.0", []string{".v2json"})

	r.GET("/health", func(c *gin.Context) {
		startupTime := time.Now().Add(-1 * time.Hour) // 示例启动时间
		status := Health{
			Status:    "healthy",
			Startup:   startupTime,
			Timestamp: time.Now(),
		}

		c.Negotiate(http.StatusOK, gin.Negotiate{
			Offered: []string{
				"application/vnd.health.json;version=1.0.0",
				"application/vnd.health.json;version=2.0.0",
				gin.MIMEJSON,
				gin.MIMEYAML,
				gin.MIMEXML,
				gin.MIMEHTML,
			},
			HTMLName: "health.html", // HTML模板名称
			HTMLData: gin.H{
				"status":    status.Status,
				"startup":   startupTime.Format(time.RFC3339),
				"timestamp": time.Now().Format(time.RFC3339),
			},
			JSONData: status,
			XMLData:  status,
			YAMLData: status,
			Data:     status,
		})
	})

	// 自定义媒体类型处理器
	r.GET("/health-custom", func(c *gin.Context) {
		startupTime := time.Now().Add(-1 * time.Hour)
		status := Health{
			Status:    "healthy",
			Startup:   startupTime,
			Timestamp: time.Now(),
		}

		accept := c.Request.Header.Get("Accept")
		
		switch accept {
		case "application/vnd.health.json;version=1.0.0":
			c.Render(http.StatusOK, CustomRenderer{
				Version: "1.0.0",
				Data:    status,
			})
		case "application/vnd.health.json;version=2.0.0":
			// 版本2.0.0的响应结构
			v2Response := map[string]interface{}{
				"health": map[string]interface{}{
					"status":    status.Status,
					"uptime":    time.Since(startupTime).String(),
					"timestamp": status.Timestamp,
				},
				"version": "2.0.0",
			}
			c.JSON(http.StatusOK, v2Response)
		default:
			c.JSON(http.StatusOK, status)
		}
	})

	// 使用NegotiateFormat的另一种方式
	r.GET("/health-negotiate", func(c *gin.Context) {
		startupTime := time.Now().Add(-1 * time.Hour)
		status := Health{
			Status:    "healthy",
			Startup:   startupTime,
			Timestamp: time.Now(),
		}

		switch c.NegotiateFormat(
			"application/vnd.health.json;version=1.0.0",
			"application/vnd.health.json;version=2.0.0",
			gin.MIMEJSON,
			gin.MIMEYAML,
			gin.MIMEXML,
		) {
		case "application/vnd.health.json;version=1.0.0":
			c.Header("Content-Type", "application/vnd.health.json;version=1.0.0")
			c.JSON(http.StatusOK, gin.H{
				"data":    status,
				"version": "1.0.0",
			})
		case "application/vnd.health.json;version=2.0.0":
			c.Header("Content-Type", "application/vnd.health.json;version=2.0.0")
			c.JSON(http.StatusOK, gin.H{
				"health": gin.H{
					"status":  status.Status,
					"details": status,
				},
				"api_version": "2.0.0",
			})
		case gin.MIMEYAML:
			c.YAML(http.StatusOK, status)
		case gin.MIMEXML:
			c.XML(http.StatusOK, status)
		default:
			c.JSON(http.StatusOK, status)
		}
	})

	// 设置HTML模板
	r.LoadHTMLGlob("templates/*")
	
	r.Run(":8080")
}

对于HTML模板(templates/health.html):

<!DOCTYPE html>
<html>
<head>
    <title>Health Status</title>
</head>
<body>
    <h1>Health Status: {{.status}}</h1>
    <p>Startup Time: {{.startup}}</p>
    <p>Current Time: {{.timestamp}}</p>
</body>
</html>

要测试不同格式的响应,可以使用curl命令:

# 请求JSON格式
curl -H "Accept: application/json" http://localhost:8080/health

# 请求XML格式
curl -H "Accept: application/xml" http://localhost:8080/health

# 请求YAML格式
curl -H "Accept: application/x-yaml" http://localhost:8080/health

# 请求自定义版本1.0.0
curl -H "Accept: application/vnd.health.json;version=1.0.0" http://localhost:8080/health

# 请求自定义版本2.0.0
curl -H "Accept: application/vnd.health.json;version=2.0.0" http://localhost:8080/health

# 请求HTML格式
curl -H "Accept: text/html" http://localhost:8080/health

这个示例展示了:

  1. 使用 gin.Negotiate 处理多种格式
  2. HTMLName 指定HTML模板文件名称
  3. 自定义媒体类型的注册和处理
  4. 通过 NegotiateFormat 手动处理内容协商
  5. 不同版本API响应的实现方式
回到顶部