GO语言项目实践2 | 青训营

40 阅读4分钟

标准库中的net/http包提供了多种创建HTTP服务器的方法,它还提供了一个基本路由器。

package main

import "net/http"

func helloWorld(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello World\n")) //[]byte声明一个字节切片并将字符串转换为字节。
}

func main()  {
    //使用方法HandFunc创建路由/,这个方法接受一个模式和一个函数,前者描述了路径,后者指定如何对发送到该路径的请求做出相应。
        http.HandleFunc("/", helloWorld)
    //为了相应客户端,使用方法ListenAndServe启动一个服务器,监听localhost和端口8000
        http.ListenAndServe(":8000", nil)
}

HandFunc创建了一个路由表,让HTTP服务器能够正确的做出响应。值的注意的是:

路由器默认将没有指定处理程序的请求定向到/。 路由器必须完全匹配,因此/us/最后的斜杠是必须要有的,如果没有,访问http://localhost:8000/us/ 将被定向到/。 路由器不关心请求的类型,而只管将与路由匹配的请求传递给相应的处理程序。

运行结果,命令行内容一直没出来,在“http://localhost:8000/” 网页上出现一句话:“Hello World”。

使用方法HandleFunc创建路由。这个方法接受一个模式和一个函数,其中前者描述了路径,而后者指定如何对发送到该路径的请求做出响应。

为响应客户端,使用方法ListenAndServe来启动一个服务器,这个服务器监听localhost和端口8000.

查看请求和响应

http.HandleFunc("/", helloWorld)
http.HandleFunc("/us/", helloWorld1)

路由器负责将路由映射到函数,但如何处理请求以及如何向客户端返回响应,是由处理程序函数定义的。处理程序函数通常先完成对请求的所有处理,再将响应返回给客户端。

启动Web浏览器,并访问http://localhost:8000/ 便可访问到。也可以不使用浏览器,使用curl来向Web服务器发送各种请求以及查看相应。

curl -is http://localhost:8000

//-is 指定打印报头

默认路由器的行为是将所有没有指定处理程序的请求都定向到/,但我们希望其返回404错误(页面未找到),因此需要在默认路由的函数中添加检查路径。

func helloWorld(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }
        w.Write([]byte("Hello World\n"))
}

创建HTTP服务器时,需要设置响应的报头,告诉客户端一些信息。假设服务器将发送一些JSON数据,通过设置Content-Type报头,可以达到这一目的。

w.Header().Set("Content-Type", "application/json; charset=utf-8")

如果服务器支持多种类型的内容,客户端可使用Accept报头请求特定类型的内容,这意味着同一个URL可能向浏览器提供HTML,而向API客户端提供JSON。

func helloWorld(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }
        switch  r.Header.Get("Accept") {
        case "application/json":
                w.Header().Set("Content-Type", "application/json; charset=utf-8")
                w.Write([]byte(`{"message": "World"}`))
        case "application/xml":
                w.Header().Set("Content-Type", "application/xml; charset=utf-8")
                w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?><Message>Hello</Message>`))
        default:
                w.Header().Set("Content-Type", "application/json; charset=utf-8")
                w.Write([]byte(`{"hello": "World"}`))
        }
}

通过curl向这个Web服务器发送请求,设置不同的类型。

curl -si -H 'Accept: application/json' http://localhost:8000
curl -si -H 'Accept: application/xml' http://localhost:8000

除了响应不同类型的内容外,HTTP服务器也需要能够响应不同类型的请求。HTTP规范中定义了四种请求包括GET/POST/PUT/DELETE。

func helloWorld(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }
        switch  r.Method {
        case "GET":
                w.Write([]byte(`{"message": "World"}`))
        case "POST":
                w.Write([]byte(`{"hello": "WoSSSrld"}`))
        default:
                //如果请求方法不是GET或POST,就发送501响应,意味着服务器不明白或不支持客户端使用的HTTP请求方法。
                w.WriteHeader(http.StatusNotImplemented)
                w.Write([]byte(http.StatusText(http.StatusNotImplemented)))
        }
}

使用curl向该服务器发送GET和POST请求。

curl -si -X  GET http://localhost:8000
curl -si -X POST http://localhost:8000

获取客户端请求中的数据很简单,但获取方式随请求类型而异。对于GET请求,其中的数据通常是通过查询字符串设置的。在POST请求中,数据通常是在请求体中发送的。

func helloWorld(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }
        switch  r.Method {
        case "GET":
                for k, v := range r.URL.Query(){
                        fmt.Println("%s: %s\n", k, v)
                }
        case "POST":
                reqBody, err := ioutil.ReadAll(r.Body)
                if err != nil{
                        log.Fatal(err)
                }
                fmt.Println("%s\n", reqBody)
        default:
                //如果请求方法不是GET或POST,就发送501响应,意味着服务器不明白或不支持客户端使用的HTTP请求方法。
                w.WriteHeader(http.StatusNotImplemented)
                w.Write([]byte(http.StatusText(http.StatusNotImplemented)))
        }
}