Skip to content

第07章:请求头与客户端信息 ​

本章目标 ​

学完本章后,你将能够:

  1. 使用 c.GetHeader() 读取请求头
  2. 使用 c.ClientIP() 获取客户端真实 IP
  3. 辨别常用请求头的作用
  4. 正确设置响应头

前置知识 ​

  • 需要先学习:第05-06章(参数读取)

7.1 读取请求头 ​

go
r.GET("/headers", func(c *gin.Context) {
	// 方式一:c.GetHeader()(推荐)
	auth := c.GetHeader("Authorization")
	contentType := c.GetHeader("Content-Type")

	// 方式二:c.Request.Header(标准库方式)
	userAgent := c.Request.Header.Get("User-Agent")

	// 遍历所有请求头
	fmt.Println("=== 所有请求头 ===")
	for key, values := range c.Request.Header {
		for _, v := range values {
			fmt.Printf("%s: %s\n", key, v)
		}
	}

	c.JSON(200, gin.H{
		"authorization": auth,
		"content_type":  contentType,
		"user_agent":    userAgent,
	})
})

7.2 常用请求头 ​

请求头含义用途
Authorization认证令牌Bearer eyJhbG...
Content-TypeBody 数据类型application/json
Accept客户端接受的响应格式application/json
User-Agent客户端标识Mozilla/5.0 ...
Cookie会话 Cookiesession_id=abc123
X-Request-ID请求追踪 ID日志关联
X-Forwarded-For代理传递的真实 IP1.2.3.4
Referer来源页面https://example.com

7.3 获取客户端 IP ​

go
r.GET("/ip", func(c *gin.Context) {
	// 推荐:自动处理代理头
	clientIP := c.ClientIP()

	// 原始方式(不推荐,拿不到代理后的真实IP)
	remoteAddr := c.Request.RemoteAddr

	c.JSON(200, gin.H{
		"client_ip":    clientIP,
		"remote_addr":  remoteAddr,
	})
})

📌 c.ClientIP() 会智能判断:先检查 X-Forwarded-For 和 X-Real-Ip 头(反向代理设置),没有才用 RemoteAddr。

让 Gin 信任代理 ​

go
// 如果服务在 Nginx 后面,设置信任代理
r.SetTrustedProxies([]string{"127.0.0.1", "10.0.0.0/8"})

7.4 设置响应头 ​

go
r.GET("/download", func(c *gin.Context) {
	// 设置单个响应头
	c.Header("Content-Disposition", "attachment; filename=report.pdf")
	c.Header("X-Custom-Header", "hello-world")

	// 多次设置同一个头会覆盖
	c.Header("X-Custom-Header", "new-value")

	c.File("./report.pdf")
})

// 预检请求处理
r.OPTIONS("/api/data", func(c *gin.Context) {
	c.Header("Access-Control-Allow-Origin", "*")
	c.Header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
	c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
	c.Status(http.StatusNoContent)
})

7.5 Content-Type 判断 ​

go
r.POST("/api", func(c *gin.Context) {
	// 方式一:c.ContentType()
	ct := c.ContentType()

	// 方式二:c.GetHeader()
	ct2 := c.GetHeader("Content-Type")

	// 判断是否是 JSON
	if ct == "application/json" {
		// 用 ShouldBindJSON
	} else if ct == "application/x-www-form-urlencoded" {
		// 用 PostForm
	}

	c.JSON(200, gin.H{
		"detected_type": ct,
		"raw_header":    ct2,
	})
})

常见错误 ​

错误1:混淆 Request Header 和 Response Header ​

go
// ❌ 在请求处理中读取响应头
r.GET("/test", func(c *gin.Context) {
	v := c.GetHeader("X-Custom")  // 读取的是"请求"头
	// 即使刚设置过响应头,GetHeader 也只读请求头
})

// ✅ 设置响应头用 c.Header()
r.GET("/test", func(c *gin.Context) {
	c.Header("X-Custom", "value")  // 设置响应头
})

错误2:拿反向代理后的 IP 用 RemoteAddr ​

go
// ❌ 如果用了 Nginx,RemoteAddr 是 Nginx 的地址(127.0.0.1)
ip := c.Request.RemoteAddr  // 永远是 127.0.0.1

// ✅ 用 ClientIP(),自动处理 X-Forwarded-For
ip := c.ClientIP()  // 真实客户端 IP

错误3:大小写问题 ​

go
// HTTP 头是大小写不敏感的,以下写法都可以:
c.GetHeader("Authorization")
c.GetHeader("authorization")
c.GetHeader("AUTHORIZATION")

// 但 Go 的 http.Header.Get() 会自动做规范化(首字母大写)
// 所以推荐用标准写法:Authorization

本章小结 ​

  • c.GetHeader("name") 读取请求头
  • c.Header("name", "value") 设置响应头
  • c.ClientIP() 获取真实客户端 IP(自动处理代理)
  • c.ContentType() 判断请求的 Content-Type
  • 常用头:Authorization(认证)、Content-Type(格式)、User-Agent(标识)

练习题 ​

  1. 写一个 /headers 接口,返回所有请求头的 JSON。
  2. 写一个 /ip 接口,分别返回 ClientIP() 和 RemoteAddr 的值。
  3. 写一个接口,根据请求的 Content-Type 返回不同的响应(JSON 请求返回 "json received",表单请求返回 "form received")。
  4. (思考题)为什么 c.ClientIP() 比 c.Request.RemoteAddr 更准确?Nginx 反向代理时发生了什么?

把零散知识,整理成可以反复走的路。