Go 语言的 net/http 包提供了一系列用于表示 HTTP 报文的结构,我们可以使用它处理请求和发送相应,其中 Request 结构代表了客户端发送的请求报文,下面让我们看一下 Request 结构体
Request 结构中的 URL 字段用于表示请求行中包含的 URL,改字段是一个指向url.URL 结构的指针,让我们来看一下 URL 结构
http://localhost:8080/hello?username=admin&password=123456
http://localhost:8080/hello?username=admin&password=123456
username=admin&password=123456
通过 Request 结果中的 Header 字段用来获取请求头中的所有信息,Header 字段的类型是 Header 类型,而 Header 类型是一个 map[string][]string,string 类型的 key,string 切片类型的值。下面是 Header 类型及它的方法:
map[User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36]
Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,ima
ge/apng,*/*;q=0.8] Accept-Encoding:[gzip, deflate, br] Accept-Language:[zhCN,zh;q=0.9,en-US;q=0.8,en;q=0.7] Connection:[keep-alive] Upgrade-InsecureRequests:[1]]
[gzip, deflate, br]
gzip, deflate, br
请求和响应的主体都是有 Request 结构中的 Body 字段表示,这个字段的类型是io.ReadCloser 接口,该接口包含了 Reader 接口和 Closer 接口,Reader 接口拥有 Read方法,Closer 接口拥有 Close 方法
<form action="http://localhost:8080/getBody" method="POST">
用户名:
<input type="text" name="username" value="hanzong">
<br/>
密 码 :
<input type="password" name="password" value="666666">
<br/>
<input type="submit">
</form>
b) 服务器处理请求的代码
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r * http.Request) {
//获取内容的长度
length: = r.ContentLength
//创建一个字节切片
body: = make([] byte, length)
//读取请求体
r.Body.Read(body)
fmt.Fprintln(w, "请求体中的内容是:", string(body))
}
func main() {
http.HandleFunc("/getBody", handler)
http.ListenAndServe(":8080", nil)
}
c) 在浏览器上显示的结果
请求体中的内容是: username=hanzong&password=666666
下面我们就通过 net/http 库中的 Request 结构的字段以及方法获取请求 URL 后面的请求参数以及 form 表单中提交的请求参数
func handler(w http.ResponseWriter, r * http.Request) {
//解析表单
r.ParseForm()
//获取请求参数
fmt.Fprintln(w, "请求参数为:", r.Form)
}
注意:在执行 r.Form 之前一定要调用 ParseForm 方法
请求参数为: map[password:[666666] username:[hanzong]]
d) 如果对 form 表单做一些修改,在 action 属性的 URL 后面也添加相同的请求参数,如下:
<form action="http://localhost:8080/getBody?username=admin&pwd=123456"
method="POST">
用 户 名 :
<input type="text" name="username" value="hanzong">
<br/>
密码:
<input type="password" name="password" value="666666">
<br/>
<input type="submit">
</form>
请求参数为:map[username:[hanzong admin] password:[666666] pwd:[123456]]
func handler(w http.ResponseWriter, r * http.Request) {
//解析表单
r.ParseForm()
//获取请求参数
fmt.Fprintln(w, "请求参数为:", r.PostForm)
}
请求参数为: map[username:[hanzong] password:[666666]]
func handler(w http.ResponseWriter, r * http.Request) {
//获取请求参数
fmt.Fprintln(w, "请求参数username的值为:", r.FormValue("username"))
}
请求参数 username 的值为: hanzong
func handler(w http.ResponseWriter, r * http.Request) {
//获取请求参数
fmt.Fprintln(w, "请求参数 username 的值为:", r.PostFormValue("username"))
}
请求参数 username 的值为: hanzong
为了取得 multipart/form-data
编码的表单数据,我们需要用到 Request 结构的ParseMultipartForm
方法和 MultipartForm 字段,我们通常上传文件时会将 form 表单的enctype 属性值设置为 multipart/form-data
<form action="http://localhost:8080/upload" method="POST" enctype="multipart/form-data">
用 户 名 :
<input type="text" name="username" value="hanzong">
<br/>
文件:
<input type="file" name="photo" />
<br/>
<input type="submit">
</form>
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r * http.Request) {
//解析表单
r.ParseMultipartForm(1024)
//打印表单数据
fmt.Fprintln(w, r.MultipartForm)
}
func main() {
http.HandleFunc("/upload", handler)
http.ListenAndServe(":8080", nil)
}
&{map[username:[hanzong]] map[photo:[0xc042126000]]}
func handler(w http.ResponseWriter, r * http.Request) {
//解析表单
r.ParseMultipartForm(1024)
fileHeader: = r.MultipartForm.File["photo"][0]
file, err: = fileHeader.Open()
if err == nil {
data,
err: = ioutil.ReadAll(file)
if err == nil {
fmt.Fprintln(w, string(data))
}
}
}
func handler(w http.ResponseWriter, r * http.Request) {
file,
_,
err: = r.FormFile("photo")
if err == nil {
data,
err: = ioutil.ReadAll(file) if err == nil {
fmt.Fprintln(w, string(data))
}
}
}
前面我们一直说的是如何使用处理器中的 *http.Request 处理用户的请求,下面我们来说一下如何使用 http.ResponseWriter 来给用户响应
func handler(w http.ResponseWriter, r * http.Request) {
w.Write([] byte("你的请求我已经收到"))
}
你的请求我已经收到
HTTP/1.1 200 OK
Date: Fri, 10 Aug 2018 01:09:27 GMT
Content-Length: 27
Content-Type: text/plain; charset=utf-8
func handler(w http.ResponseWriter, r * http.Request) {
html: = `<html>
<head>
<title>测试响应内容为网页</title>
<meta charset="utf-8"/>
</head>
<body>
我是以网页的形式响应过来的!
</body>
</html>`
w.Write([] byte(html))
}
我是以网页的形式响应过来的!
HTTP/1.1 200 OK
Date: Fri, 10 Aug 2018 01:26:58 GMT
Content-Length: 194
Content-Type: text/html; charset=utf-8
func handler(w http.ResponseWriter, r * http.Request) {
//设置响应头中内容的类型
w.Header().Set("Content-Type", "application/json")
user: = User {
ID: 1,
Username: "admin",
Password: "123456",
}
//将 user 转换为 json 格式
json, _: = json.Marshal(user)
w.Write(json)
}
{"ID":1,"Username":"admin","Password":"123456"}
HTTP/1.1 200 OK
Content-Type: application/json
Date: Fri, 10 Aug 2018 01:58:02 GMT
Content-Length: 47
func handler(w http.ResponseWriter, r * http.Request) {
//以下操作必须要在 WriteHeader 之前进行
w.Header().Set("Location", "https:www.baidu.com")
w.WriteHeader(302)
}
HTTP/1.1 302 Found
Location: https:www.baidu.com
Date: Fri, 10 Aug 2018 01:45:04 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8