Go实现HTTP服务

Golang创建一个简单的http服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"net/http"
)

func hello(resp http.ResponseWriter, req *http.Request) {
fmt.Fprintf(resp, "hello")
}

func main() {
// 创建http监听 路径 方法
http.HandleFunc("/", hello)
// 配置监听地址 ListenAndServe会一直处于挂起状态
err := http.ListenAndServe("0.0.0.0:8888", nil)
if err != nil {
fmt.Printf("http err:%s\n", err)
}
}

发送一个Http请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"fmt"
"net/http"
"net/http/httputil"
)

// http client
func main() {
res, err := http.Get("http://www.baidu.com/")
if err != nil {
fmt.Println("get err:", err)
return
}
data, err := httputil.DumpResponse(res, true)
if err != nil {
fmt.Println("get data err:", err)
return
}
fmt.Println(string(data))
}

HTTP常见的请求方法:GET、POST、PUT、DELETE、HEAD

发送一个HEAD请求

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
package main

import (
"fmt"
"net/http"
)

var urls = []string{
"http://www.baidu.com/",
"http://www.google.com",
"http://www.taobao.com",
}

// head 测试url是否能打开
func main() {
for _, url := range urls {
resp, err := http.Head(url)
if err != nil {
fmt.Println("request err:", err)
continue
}
fmt.Printf("head %s success,status:%d\n", url, resp.StatusCode)
}
}

HEAD请求如果对应URL长时间没有响应,会触发超时处理

自定义HEAD超时时间

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
package main

import (
"fmt"
"net"
"net/http"
"time"
)

var urls = []string{
"http://www.baidu.com/",
"http://www.google.com",
"http://www.taobao.com",
}

func main() {
// 自定义超时时间
c := http.Client{
Transport: &http.Transport{
Dial: func(network, addr string) (conn net.Conn, err error) {
timeout := time.Second * 3
return net.DialTimeout(network, addr, timeout)
},
},
}

for _, url := range urls {
resp, err := c.Head(url)
if err != nil {
fmt.Println("request err:", err)
continue
}
fmt.Printf("head %s success,status:%d\n", url, resp.StatusCode)
}
}

简单的表单处理:

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
package main

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

// 表单处理

func hello(respWrite http.ResponseWriter, req *http.Request) {
io.WriteString(respWrite, "hello world ")
}

func loginHandle(respWrite http.ResponseWriter, req *http.Request) {
var form = `<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="#" method="POST">
<input type="text" name="username">
<input type="text" name="passwd">
<input type="submit" value="登录">
</form>
</body>
</html>`
respWrite.Header().Set("content-type", "text/html; charset=UTF-8")
switch req.Method {
case "GET":
io.WriteString(respWrite, form)
case "POST":
req.ParseForm()
io.WriteString(respWrite, req.FormValue("username"))
io.WriteString(respWrite, "\n")
io.WriteString(respWrite, req.FormValue("passwd"))

}
}

func main() {
http.HandleFunc("/", hello)
http.HandleFunc("/login", loginHandle)
if err := http.ListenAndServe(":8888", nil); err != nil {
fmt.Println("http server start err:", err)
}
}

如果不进行panic处理,某一次请求发生了panic,则会导致整个http服务终止

panic处理

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
package main

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

func loginHandle(respWriter http.ResponseWriter, req *http.Request) {
io.WriteString(respWriter, "login")
panic("login err")

}

// panic 处理
func logPanicHandle(hand http.HandlerFunc) http.HandlerFunc {
return func(respWriter http.ResponseWriter, req *http.Request) {

defer func() {
if err := recover(); err != nil {
log.Printf("[%v] url:[%v] panic: %v", req.RemoteAddr, req.RequestURI, err)
}
}()

hand(respWriter, req)
}
}

func main() {
http.HandleFunc("/login", logPanicHandle(loginHandle))
err := http.ListenAndServe(":8888", nil)
if err != nil {
fmt.Println("server err:", err)
}
}