2.2goweb解析http请求信息

Go语言的net/http包提供了一些列用于表示HTTP报文的解构。我们可以使用它处理请求和发送响应。其中request结构体代表了客户端发生的请求报文。

核心字段获取方法

1. 请求行信息

通过 http.Request 结构体获取:

Go 复制代码
func handler(w http.ResponseWriter, r *http.Request) {
    // 请求方法(GET/POST等)
    fmt.Println("Method:", r.Method)  
    
    // 完整URL
    fmt.Println("URL:", r.URL.String())  

    urlPath := r.URL.Path       // 请求路径(如 "/api/data")
    fmt.Println("请求路径:",urlPath) 

//直接获取原始查询字符串
    rawQuery := r.URL.RawQuery 
    fmt.Fprintf(w, "Raw Query: %s", rawQuery)
// 方法2:直接获取已解析的 Values(推荐)
    values := r.URL.Query()
//url.Values 类型:本质是 map[string][]string,支持多值参数(如 ?tags=go&tags=web)
    tags := values["tags"] // 返回字符串切片 []string{"go", "web"}
    fmt.Println("查询字符串tags:", tags ) 

    q := values.Get("q") // 返回第一个值,若不存在则返回空字符串 
    fmt.Println("查询字符串q:", q) 

    if page, ok := values["page"]; ok {
        // 参数存在 
        fmt.Println("page参数存在:", page)
    }else{
         fmt.Println("page参数不存在,需要给出默认值:", page)
    }

    // 协议版本
    fmt.Println("Protocol:", r.Proto)  
}

RawQuery 中的参数是 已编码 的(如空格为 %20),需使用 url.QueryUnescape 解码:

decoded, _ := url.QueryUnescape(r.URL.RawQuery)

频繁操作查询参数时,优先使用 r.URL.Query() 缓存解析结果,避免重复解析。

2. 请求头信息

使用 Header 字段读取:

规范化的头字段名

Go 会自动将头字段名规范化(首字母大写),例如:

  • user-agentUser-Agent
  • content-typeContent-Type
Go 复制代码
//1. 获取单个头信息值
//Get() 方法:返回指定键的第一个值(适用于单值头字段)。

encoding := r.Header.Get("Accept-Encoding") // 返回 "gzip"

//直接访问 map:获取值的切片(需处理空值情况)。

if values := r.Header["User-Agent"]; len(values) > 0 {{
    userAgent = values[0]
}}

// 获取多值头信息
//Values() 方法(Go 1.14+):返回所有值的切片。
encodings := r.Header.Values("Accept-Encoding") // ["gzip", "deflate"]



// 遍历所有头部
for key, values := range r.Header {
    fmt.Printf("%s: %v\n", key, values)
}
3. 查询参数(URL 参数)

手动解析 URL 中的 Query 参数:

Go 复制代码
// 方法:手动解析(需处理错误)
decoded, _ := url.QueryUnescape(r.URL.RawQuery)
values, err := url.ParseQuery(decoded)
if err != nil {
    http.Error(w, "Invalid query", http.StatusBadRequest)
    return 
}
 
4. 请求体内容

根据 Content-Type 处理不同格式的请求体:

Go 复制代码
// 读取全部内容(适用于小数据)
body, err := ioutil.ReadAll(r.Body)
if err != nil {
    http.Error(w, "Read body failed", http.StatusBadRequest)
    return
}
fmt.Println("Body:", string(body))

// 关闭Body(必须)
defer r.Body.Close()

a. 表单数据(Form Data)

Go 复制代码
err := r.ParseForm()                 // 显式解析表单 
username := r.FormValue("username")  // 获取单个字段(也可以获取url传递过来的参数) 
allFormData := r.PostForm            // 获取全部表单数据(map类型,不含url传递过来的参数)
allFormData2 := r.Form       // 获取全部表单数据(map类型,包含url传递过来的参数)

FormValue会隐式调用解析。

例子:

html 复制代码
    <div class="login-container">
        <h2>系统登录</h2>
        <form action="/api?username=lisi&pwd=wangwu" method="post">
            <div class="form-group">
                <label>用户名:</label>
                <input type="text" name="uname" value="赵六" required>
            </div>
            <div class="form-group">
                <label>密码:</label>
                <input type="password" name="pwd" value="123" required>
            </div>
            <button class="btn-login" type="submit">登录</button>
        </form>
    </div>
html 复制代码
func apiHandler(w http.ResponseWriter, r *http.Request) {
	username1 := r.FormValue("username")
	uname1 := r.FormValue("uname")
	pwd1 := r.FormValue("pwd")
	allFormData := r.PostForm
	username2 := allFormData["username"]
	uname2 := allFormData["uname"]
	pwd2 := allFormData["pwd"]
	allData := r.Form
	username3 := r.Form["username"]
	uname3 := r.Form["uname"]
	pwd3 := r.Form["pwd"]
	fmt.Println("FormValue方法:", username1, uname1)
	fmt.Println("FormValue方法:", pwd1)
	fmt.Println("==========")
	fmt.Println("PostForm:", allFormData)
	fmt.Println("PostForm:", username2, uname2)
	fmt.Println("PostForm:", pwd2)
	fmt.Println("==========")
	fmt.Println("allData:", allData)
	fmt.Println("allData:", username3, uname3)
	fmt.Println("allData:", pwd3)

}

b. JSON 数据

Go 复制代码
body, _ := io.ReadAll(r.Body)        // 读取原始Body 
var data map[string]interface{}
json.Unmarshal(body, &data)           // 反序列化到结构体 

c. 文件上传(Multipart)

Go 复制代码
package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    // 限制请求体大小(防大文件攻击)
    r.ParseMultipartForm(10 << 20) // 10MB

    // 获取普通表单字段
    title := r.FormValue("title")

    // 处理文件上传
    file, _, err := r.FormFile("file")
    if err != nil {
        http.Error(w, "文件上传失败", http.StatusBadRequest)
        return
    }
    defer file.Close()

    // 保存文件
    data, _ := ioutil.ReadAll(file)
    ioutil.WriteFile("/uploads/"+title, data, 0644)

    fmt.Fprintln(w, "上传成功")
}

func main() {
    http.HandleFunc("/upload", uploadHandler)
    http.ListenAndServe(":8080", nil)
}
相关推荐
用户342323237631714 小时前
开源!Go+Wails+Vue3 手搓一个 PLC 实时监控桌面工具
go
止语Lab14 小时前
为什么你的 Go TCP server P99 延迟这么高
go
Andy Dennis21 小时前
nsq学习记录
消息队列·go·nsq
韦胖漫谈IT1 天前
选语言不是站队,是选适合问题的工具
java·python·ai·rust·go·技术落地
喵个咪1 天前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
夜悊2 天前
Go网络编程的学习代码示例:客户端/服务端(C/S)模型
go
审判长烧鸡2 天前
【AI问答】GO代码循环返值
go
捧 花2 天前
Eino框架记忆功能实现指南
go·agent·eino
Java陈序员2 天前
主流数据库通吃!一款开源实用的数据库备份管理工具!
react.js·postgresql·go
云浪2 天前
搞懂 Go WaitGroup:一篇文章彻底理解并发等待机制
后端·go