美文网首页
用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