1.HTTP報(bào)文結(jié)構(gòu)
HTTP分為請(qǐng)求和響應(yīng)類型割粮,都具有相同的結(jié)構(gòu):
1.請(qǐng)求行或者響應(yīng)行
2.0個(gè)或者多個(gè)首部
3.一個(gè)空行
4.一個(gè)可選的報(bào)文主體
1.1Request結(jié)構(gòu)
Request結(jié)構(gòu)表示一個(gè)客戶端發(fā)送的HTTP請(qǐng)求報(bào)文捕虽,該結(jié)構(gòu)包含了報(bào)文經(jīng)過語法分析后較為重要的信息涕侈。
組成:
1.URL字段
2.Header字段
3.Body字段
4.Form字段
5.PostForm字段
6.MultipartForm字段
通過該結(jié)構(gòu)汁针,可以對(duì)請(qǐng)求報(bào)文中的cookie,url代理等進(jìn)行訪問。
1.1.1URL字段
表示請(qǐng)求中包含的URL粹胯,該字段是一個(gè)指向url.URL結(jié)構(gòu)的指針下隧。定義如下:
type URL struct {
Scheme string
Opaque string // encoded opaque data
User *Userinfo // username and password information
Host string // host or host:port
Path string // path (relative paths may omit leading slash)
RawPath string // encoded path hint (see EscapedPath method)
ForceQuery bool // append a query ('?') even if RawQuery is empty
RawQuery string // encoded query values, without '?'
Fragment string // fragment for references, without '#'
}
1.1.2Header字段
請(qǐng)求和響應(yīng)的首部都使用Header類型描述。
package main
import (
"net/http"
"fmt"
)
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/headers", headers)
server.ListenAndServe()
}
func headers(w http.ResponseWriter, r *http.Request) {
h := r.Header
fmt.Fprintln(w, h)
}
代碼中的r.Header即把請(qǐng)求首部讀取出來攻走,并寫入response返回給客戶端殷勘。
可以使用指定鍵獲得Header中的值,如:
//獲得字符串切片
h := r.Header["Accept-Encoding"]
//獲得字符串昔搂,使用逗號(hào)分隔開
h := r.Header.Get("Accept-Encoding")
1.1.3Body字段
請(qǐng)求和響應(yīng)的主體都由Request結(jié)構(gòu)的Body字段表示玲销,該字段是一個(gè)io.ReadCloser接口。
使用Read方法讀取主體的內(nèi)容:
func main() {
server := http.Server{
Addr: "localhost:8080",
}
http.HandleFunc("/body", body)
server.ListenAndServe()
}
func body(w http.ResponseWriter, r *http.Request) {
len := r.ContentLength//獲取主體數(shù)據(jù)的字節(jié)長度
body := make([]byte, len)//根據(jù)長度創(chuàng)建出字節(jié)數(shù)組
r.Body.Read(body)//將主體數(shù)據(jù)讀取到body中
fmt.Fprintln(w, string(body))
}
在終端使用cURL命令即可模擬POST請(qǐng)求
yuhua$ curl -id "body" localhost:8080/body
輸出如下內(nèi)容:
HTTP/1.1 200 OK
Date: Mon, 25 Jun 2018 15:12:11 GMT
Content-Length: 5
Content-Type: text/plain; charset=utf-8
body
1.1.4Form字段
通過調(diào)用Request提供的方法摘符,用戶可以將URL贤斜,主體等數(shù)據(jù)提取到Form,PostForm,MultipartForm等字段中。下面代碼調(diào)用了ParseForm方法逛裤,訪問時(shí)瘩绒,就應(yīng)該訪問相應(yīng)的Form字段。
func main() {
server := http.Server{
Addr: "localhost:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
func process(w http.ResponseWriter, r *http.Request) {
r.ParseForm()//對(duì)表單進(jìn)行分析
fmt.Fprintln(w, r.Form)
}
編寫好html文件别凹,用瀏覽器打開:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>GoWeb</title>
</head>
<form action=http://127.0.0.1:8080/process?hello=world&thread=123 method="post" enctype="application/x-www-form-urlencoded">
<input type="text" name="hello" value="sau"/>
<input type="text" name="post" value="456"/>
<input type="submit">
</form>
</html>
點(diǎn)擊提交后草讶,得到如下結(jié)果:
map[post:[456] hello:[sau world] thread:[123]]
我們發(fā)現(xiàn),使用application/x-www-form-urlencoded格式炉菲,最終的Form字段會(huì)包含URL與body中的值堕战。
2.ResponseWrite
ResponseWrite是一個(gè)接口坤溃,處理器通過該接口創(chuàng)建HTTP響應(yīng)。
該接口有3個(gè)方法:
1.Write
2.WriteHeader
3.Header
2.1Write
package main
import "net/http"
func main() {
server := http.Server{
Addr: "localhost:8080",
}
http.HandleFunc("/write", write)
server.ListenAndServe()
}
func write(w http.ResponseWriter, r *http.Request) {
str := `<html><head><title>Go Web</title></head><body><h1>Hello World</h1></body></html>`
w.Write([]byte(str))
}
瀏覽器瀏覽后:
2.2WriteHeader
將狀態(tài)碼寫入返回中嘱丢。如:你定義一個(gè)API薪介,但是沒有實(shí)現(xiàn),當(dāng)客戶端訪問時(shí)越驻,可以返回501汁政。
package main
import (
"net/http"
"fmt"
)
func main() {
server := http.Server{
Addr: "localhost:8080",
}
http.HandleFunc("/write", write)
http.HandleFunc("/writeHeader", writeHeader)
server.ListenAndServe()
}
func write(w http.ResponseWriter, r *http.Request) {
str := `<html><head><title>Go Web</title></head><body><h1>Hello World</h1></body></html>`
w.Write([]byte(str))
}
func writeHeader(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(501)//該方法只允許設(shè)置一次,不允許多次設(shè)置
fmt.Fprintln(w, "沒有實(shí)現(xiàn)缀旁!")
}
訪問后:
2.3Header
調(diào)用Header方法记劈,可以取得一個(gè)由首部組成的映射,修改該映射就可以修改首部并巍,修改后的首部被包含在HTTP響應(yīng)里目木,并隨著響應(yīng)一同發(fā)送至客戶端。
package main
import (
"net/http"
"fmt"
)
func main() {
server := http.Server{
Addr: "localhost:8080",
}
http.HandleFunc("/write", write)
http.HandleFunc("/writeHeader", writeHeader)
http.HandleFunc("/header", header)
server.ListenAndServe()
}
func write(w http.ResponseWriter, r *http.Request) {
str := `<html><head><title>Go Web</title></head><body><h1>Hello World</h1></body></html>`
w.Write([]byte(str))
}
func writeHeader(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(501)
fmt.Fprintln(w, "沒有實(shí)現(xiàn)懊渡!")
}
func header(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", "http://www.baidu.com")
w.WriteHeader(302)
}
瀏覽器打開會(huì)自動(dòng)跳轉(zhuǎn)到百度頁面刽射。
2.4返回JSON
返回Back結(jié)構(gòu)體JSON。
package main
import (
"net/http"
"fmt"
json2 "encoding/json"
)
func main() {
server := http.Server{
Addr: "localhost:8080",
}
http.HandleFunc("/write", write)
http.HandleFunc("/writeHeader", writeHeader)
http.HandleFunc("/header", header)
http.HandleFunc("/json", jsonBack)
server.ListenAndServe()
}
func write(w http.ResponseWriter, r *http.Request) {
str := `<html><head><title>Go Web</title></head><body><h1>Hello World</h1></body></html>`
w.Write([]byte(str))
}
func writeHeader(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(501)
fmt.Fprintln(w, "沒有實(shí)現(xiàn)剃执!")
}
func header(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", "http://www.baidu.com")
w.WriteHeader(302)
}
type back struct {
User string
Threads []string
}
func jsonBack(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Conten-Type", "application/json")
back := &back{
User: "Sau",
Threads: []string{"first", "second", "third"},
}
json, _ := json2.Marshal(back)
w.Write(json)
}
瀏覽器瀏覽后返回: