美文网首页
用Go语言实现Hello World HTTP服务器

用Go语言实现Hello World HTTP服务器

作者: louyang | 来源:发表于2021-06-17 10:44 被阅读0次

1 引子

$ curl localhost:6666

当我们执行下面curl命令时,curl程序会发送一条HTTP Request:

GET / HTTP/1.1
Host: localhost:6666
User-Agent: curl/7.68.0
Accept: */*

我们接下来的实验就是用Go语言写一个简单的HTTP服务器,来处理这条HTTP Request.

2 注册回调函数并启动服务器

    http.HandleFunc("/", helloWorld)   <- 关联URL与回调函数
    log.Fatal(http.ListenAndServe(":6666", nil))   <- 监听端口并启动服务器

完整例子:

package main

import (
    "log"
    "net/http"
)

func helloWorld(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello World!\n"))
}

func main() {
    http.HandleFunc("/", helloWorld)
    log.Fatal(http.ListenAndServe(":6666", nil))
}

打开一个终端窗口,启动HTTP服务器:

$ go run server_1.go

在另外一个终端窗口中运行curl命令:

$ curl localhost:6666
Hello World!

重复启动此服务器时,因为端口6666已被占用,会报错:

$ go run server_1.go
2021/06/17 05:44:04 listen tcp :6666: bind: address already in use
exit status 1

3 服务器端得到更多信息

$ curl -X "POST" localhost:6667/path -d "content"

如果我们把curl命令改的在复杂一点,那么发出去的HTTP Reqeust将带有更多信息:

POST /path HTTP/1.1
Host: localhost:6666
User-Agent: curl/7.68.0
Accept: */*
Content-Length: 7
Content-Type: application/x-www-form-urlencoded

content

其中,POST称为HTTP Method,/path称为URL,content时HTTP body,在服务器端怎么得到这些信息呢,再看一个完整的例子:

package main

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

func helloWorld(w http.ResponseWriter, r *http.Request) {
    log.Print("URL:", r.URL.Path)
    log.Print("Method:", r.Method)

    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        log.Print("Error reading body: %v", err)
        return
    }
    log.Print("Body:", string(body))

    w.Write([]byte("Hello World!\n"))
}

func main() {
    http.HandleFunc("/", helloWorld)
    log.Fatal(http.ListenAndServe(":6666", nil))
}

接到HTTP Reqeust后,服务器端打印如下:

2021/07/23 09:00:37 URL:/path
2021/07/23 09:00:37 Method:POST
2021/07/23 09:00:37 Body:content

4 处理HTTP Body

ioutil.ReadAll读完一次以后,再读就没数据了。
假设我们有多个检查处理步骤,第一步处理完后,再将body交给下一步处理,我们可以这样。

package main

import (
    "net/http"
    "io/ioutil"
    "bytes"
    "log"
)

func helloWorld(w http.ResponseWriter, r *http.Request) {
    log.Print("URL:", r.URL.Path)
    log.Print("Method:", r.Method)

    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        log.Print("Error reading body: %v", err)
        return
    }
    log.Print("Body(1st):", string(body))

    r.Body = ioutil.NopCloser(bytes.NewBuffer(body))

    body, err = ioutil.ReadAll(r.Body)
    if err != nil {
        log.Print("Error reading body: %v", err)
        return
    }
    log.Print("Body(2nd):", string(body))

    w.Write([]byte("Hello World!\n"))
}

func main() {
    http.HandleFunc("/", helloWorld)
    log.Fatal(http.ListenAndServe(":6666", nil))
}

运行结果:

2021/07/23 09:16:19 URL:/path
2021/07/23 09:16:19 Method:POST
2021/07/23 09:16:19 Body(1st):content
2021/07/23 09:16:19 Body(2nd):content

5 当HTTP Body为Json格式时

package main

import (
    "net/http"
    "encoding/json"
    "log"
)

type UserRequest struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

func helloWorld(w http.ResponseWriter, r *http.Request) {
    var req UserRequest
    err := json.NewDecoder(r.Body).Decode(&req)
    if err != nil {
        http.Error(w, err.Error(), 400)
        return
    }

    w.Write([]byte("Hello " + req.Name + "\n"))
}

func main() {
    http.HandleFunc("/", helloWorld)
    log.Fatal(http.ListenAndServe(":6666", nil))
}

执行crul命令的窗口,准备一个a.json,内容为:

{"Name": "Lane","Email": "123456@qq.com"}
$ curl localhost:6666/path -d @./a.json
Hello Lane

参考

https://yourbasic.org/golang/http-server-example/
https://www.honeybadger.io/blog/go-web-services/
https://zetcode.com/golang/http-server/
https://www.informit.com/articles/article.aspx?p=2861456&seqNum=7
https://stackoverflow.com/questions/43021058/golang-read-request-body
https://stackoverflow.com/questions/46948050/how-to-read-request-body-twice-in-golang-middleware

相关文章

网友评论

      本文标题:用Go语言实现Hello World HTTP服务器

      本文链接:https://www.haomeiwen.com/subject/qqaqyltx.html