1.HTTP报文结构
HTTP分为请求和响应类型,都具有相同的结构:
1.请求行或者响应行
2.0个或者多个首部
3.一个空行
4.一个可选的报文主体
1.1Request结构
Request结构表示一个客户端发送的HTTP请求报文,该结构包含了报文经过语法分析后较为重要的信息。
组成:
1.URL字段
2.Header字段
3.Body字段
4.Form字段
5.PostForm字段
6.MultipartForm字段
通过该结构,可以对请求报文中的cookie,url代理等进行访问。
1.1.1URL字段
表示请求中包含的URL,该字段是一个指向url.URL结构的指针。定义如下:
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字段
请求和响应的首部都使用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即把请求首部读取出来,并写入response返回给客户端。
可以使用指定键获得Header中的值,如:
//获得字符串切片
h := r.Header["Accept-Encoding"]
//获得字符串,使用逗号分隔开
h := r.Header.Get("Accept-Encoding")
1.1.3Body字段
请求和响应的主体都由Request结构的Body字段表示,该字段是一个io.ReadCloser接口。
使用Read方法读取主体的内容:
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//获取主体数据的字节长度
body := make([]byte, len)//根据长度创建出字节数组
r.Body.Read(body)//将主体数据读取到body中
fmt.Fprintln(w, string(body))
}
在终端使用cURL命令即可模拟POST请求
yuhua$ curl -id "body" localhost:8080/body
输出如下内容:
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字段
通过调用Request提供的方法,用户可以将URL,主体等数据提取到Form,PostForm,MultipartForm等字段中。下面代码调用了ParseForm方法,访问时,就应该访问相应的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()//对表单进行分析
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>
点击提交后,得到如下结果:
map[post:[456] hello:[sau world] thread:[123]]
我们发现,使用application/x-www-form-urlencoded格式,最终的Form字段会包含URL与body中的值。
2.ResponseWrite
ResponseWrite是一个接口,处理器通过该接口创建HTTP响应。
该接口有3个方法:
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
将状态码写入返回中。如:你定义一个API,但是没有实现,当客户端访问时,可以返回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)//该方法只允许设置一次,不允许多次设置
fmt.Fprintln(w, "没有实现!")
}
访问后:
2.3Header
调用Header方法,可以取得一个由首部组成的映射,修改该映射就可以修改首部,修改后的首部被包含在HTTP响应里,并随着响应一同发送至客户端。
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, "没有实现!")
}
func header(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", "http://www.baidu.com")
w.WriteHeader(302)
}
浏览器打开会自动跳转到百度页面。
2.4返回JSON
返回Back结构体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, "没有实现!")
}
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)
}
浏览器浏览后返回: