trainingDiary_6

2019-12-19-go web随笔

go web 接收请求

这个其实我昨天已经看过了一点,但昨天看的很杂,今天把它全部重新整理了一遍,内容如下:

http.ListenAndServe()的接收请求,输出响应的流程如下:
首先调用Http.HandleFunc

按顺序做了几件事:

1 调用了DefaultServeMux的HandleFunc

2 调用了DefaultServeMux的Handle

3 往DefaultServeMux的map[string]muxEntry中增加对应的handler和路由规则

其次调用http.ListenAndServe(“:9090”, nil)

按顺序做了几件事情:

1 实例化Server

2 调用Server的ListenAndServe()

3 调用net.Listen(“tcp”, addr)监听端口

4 启动一个for循环,在循环体中Accept请求

5 对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务go c.serve()

6 读取每个请求的内容w, err := c.readRequest()

7 判断handler是否为空,如果没有设置handler(这个例子就没有设置handler),handler就设置为DefaultServeMux

8 调用handler的ServeHttp

9 在这个例子中,下面就进入到DefaultServeMux.ServeHttp

10 根据request选择handler,并且进入到这个handler的ServeHTTP
mux.handler(r).ServeHTTP(w, r)

11 选择handler:

A 判断是否有路由能满足这个request(循环遍历ServerMux的muxEntry)

B 如果有路由满足,调用这个路由handler的ServeHttp

C 如果没有路由满足,调用NotFoundHandler的ServeHttp

流程图如下:
avatar

go web处理请求数据

在Go语言中,使用http.Request结构来处理http请求的数据,在我们定义处理请求的方法,会传入http.Request的实例,如下代码中request就是代表一个请求的实例。

1
2
3
http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
//使用request可以获取http请求的数据
})

request公开可访问字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
type Request struct {
Method string //方法:POST,GET...
URL *url.URL //URL结构体
Proto string // 协议:"HTTP/1.0"
ProtoMajor int // 1
ProtoMinor int // 0
Header Header //头部信息
Body io.ReadCloser //请求实体
GetBody func() (io.ReadCloser, error) // Go 1.8
ContentLength int64 //首部:Content-Length
TransferEncoding []string
Close bool //是否已关闭
Host string //首部Host
Form url.Values //参数查询的数据
PostForm url.Values // application/x-www-form-urlencoded类型的body解码后的数据
MultipartForm *multipart.Form //文件上传时的数据
Trailer Header
RemoteAddr string //请求地址
RequestURI string //请求的url地址
TLS *tls.ConnectionState
Cancel <-chan struct{} //
Response *Response // 响应数据
}
```


### 获得请求头(Header)

``` go
http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
request.RemoteAddr
request.RequestURI
request.ContentLength
request.Proto
request.Method
request.Referer()
request.UserAgent()
})
```

### 获取查询参数(Query)

``` go
获取查询参数(url中?后面使用&分隔的部分),用request.FormValue(key)方法获取查询参数,其中key为参数的名称,代码如下:

package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
username := request.FormValue("username")
gender := request.FormValue("gender")
fmt.Fprintln(writer,fmt.Sprintf("用户名:%s,性别:%s",username,gender))
})
fmt.Println(http.ListenAndServe(":8080",nil))
}
```

### 获取表单信息(Form)
我们说获取表单信息,一般是指获取Content-Type是application/x-www-form-urlencoded或multipart/form-data时,请求实体中的数据,如果你有做传统网页中的表单提交数据的经历,相信对这两种提交数据的方式应该是熟悉的,而multipart/form-data一般是用来上传文件的。

application/x-www-form-urlencoded
获取Content-Type为application/x-www-form-urlencoded时提交上来的数据,可以使用request.PostForm字段request.Form和request.PostFormValue(key)方法获取,但必须先调用request.ParseForm()将数据写入request.PostForm字段中。

使用request.ParseForm()函数解析body参数,这时会将参数写入Form字段和PostForm字段当中。
使用request.Form、request.PostForm或request.PostFormValue(key)都可以获取
request.Form和request.PostForm的类型url.Values,结构定义如下
``` go
type Values map[string][]string
```

``` go
package main
import (
"fmt"
"net/http"
)
func main(){
http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
err := request.ParseForm()
if err != nil{
fmt.Fprintln(writer,"解析错误")
}
username1 := request.PostForm["username"][0]
username2 := request.PostFormValue("username")
username3 := request.Form["username"][0]
fmt.Fprintln(writer,fmt.Sprintf("username1:%s,username2:%s,usernam3:%s",username1,username2,username3))
})
fmt.Println(http.ListenAndServe(":8080",nil))
}

multipart/form-data

获取Content-Type为multipart/form-data时提交上来的数据
使用request.ParseMultipartForm(maxMemory),解析参数,将参数写入到MultipartForm字段当中,其中maxMemory为上传文件最大内存。
使用request.FormFile(文件域),可以获取上传的文件对象:multipart.File
除了文件域,其中参数可以从request.PostForm字段获取,注意,此时不需要再调用request.ParseForm()了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/upload", func(writer http.ResponseWriter, request *http.Request) {
err := request.ParseMultipartForm(32 << 20)
if err != nil {
fmt.Fprintln(writer,"文件上传错误")
return
}
fmt.Println(request.FormFile("file"))
})
fmt.Println(http.ListenAndServe(":8080",nil))
}

上头介绍的都是表单提交方式,
但在现在前后端分离开发趋势和APP开发中,Content-Type指application/json才是更常见的数据提交方式。