18.创建HTTP服务器

通过Hello World Web服务器宣告你的存在

package main

import(
    "net/http"
)

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

func main(){
    http.HandleFunc("/",helloWorld)
    http.ListenAndServe(":8000",nil)
}
  • 导入net/http包
  • 在main函数中,使用方法HandleFunc创建了路由/,这个方法接受一个模式和一个函数,其中前者描述了路径,而后者指定如何对发送到该路径的请求做出响应
  • 函数helloWorld接受一个http.ResponseWriter和一个指向请求的指针。这意味着在这个函数中,可产看或操作请求,再将相应返回给客户端。在这里,使用了方法Write来生成相应,这个方法生成的HTTP响应包含状态、报头和响应体。[]byte声明了一个字节切片并将字符串值转为字节。这意味着方法Write可以使用[]byte,因为这个方法将一个字节切片作为参数
  • 为响应客户端,使用了方法ListenAndServe来启动一个服务器,这个服务器监听localhost和端口8000

查看请求和响应

使用GIT发出请求

可以使用GIT工具来对服务器发出请求,这样就不用打开浏览器

//运行服务器
go run test.go
//使用gitBash发出请求
curl -is http://localhost:8000

//结果
//HTTP/1.1 200 OK
//Date: Thu, 28 Jan 2021 14:21:46 GMT
//Content-Length: 12
//Content-Type: text/plain; charset=utf-8

//Hello world
  • 这个响应使用的协议是HTTP1.1,状态码为200
  • 报头Date详细地描述了响应的发送时间
  • 报头Content-Length详细的指出了响应的长度,为12字节
  • 报头Content-Type指出了内容的类型以及使用的编码
  • 最后输出的是响应体,这里是hello world

详谈路由

HandleFunc用于注册对URL地址映射进行响应的函数

  • 路由器默认将没有指定处理程序的请求定向到/
  • 路由必须完全匹配,例如:对于向/users发出的请求,将定向到/,因为这里末尾少了斜杠
  • 路由器不关心请求的类型,而只管将路由匹配的请求传递给响应的处理程序

处理404错误

默认路由器的行为是将所有没有指定处理程序的请求都定向到/,因此我们可以对前面的程序进行修改,让它在路径不存在时,返回404错误

package main

import(
    "net/http"
)

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

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

// $ curl -is http://localhost:8000
// HTTP/1.1 200 OK
// Date: Thu, 28 Jan 2021 14:30:33 GMT
// Content-Length: 12
// Content-Type: text/plain; charset=utf-8

// Hello world

// $ curl -is http://localhost:8000/user
// HTTP/1.1 404 Not Found
// Content-Type: text/plain; charset=utf-8
// X-Content-Type-Options: nosniff
// Date: Thu, 28 Jan 2021 14:30:57 GMT
// Content-Length: 19

// 404 page not found

设置报头

在创建HTTP服务器时,经常需要设置响应的报头

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

只要这行代码是在响应被发送给客户端之前执行的,这个报头就会被添加到响应中

package main

import(
    "net/http"
)

func helloWorld(w http.ResponseWriter,r *http.Request){
    if r.URL.Path !="/"{
        http.NotFound(w,r)
        return 
    }
    w.Header().Set("Content-Type","application/json;charset=utf-8")
    w.Write([]byte("Hello world\n"))
}

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

// $ curl -is http://localhost:8000
// HTTP/1.1 200 OK
// Content-Type: application/json;charset=utf-8
// Date: Thu, 28 Jan 2021 14:45:03 GMT
// Content-Length: 12

// Hello world

响应以不同类型的内容

响应客户端时,HTTP服务器通常提供多种类型的内容。一些常用的内容类型包括text/plain、text/html、application/json和application/xml。如果服务器支持多种类型的内容,客户端可使用Accept报头请求特定类型的内容。这意味着同一个URL可能向浏览器提供HTML

package main

import(
    "net/http"
)

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":"Hello World"}`))
    case "application/xml":
        w.Header().Set("Content-Type","application/xml;charset =utf-8")
        w.Write([]byte(`<? xml version = ” 1. 。” encoding = ” utf -
8 ” 节><Message>Hello World</Message >、`))
    default:
        w.Header().Set("Content-Type","text/plain;charset=utf-8")
        w.Write([]byte("hello World"))
    }
}

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

// $ curl -is http://localhost:8000 -H "Accept:application/json"
// HTTP/1.1 200 OK
// Content-Type: application/json ; charset=utf-8
// Date: Thu, 28 Jan 2021 15:02:20 GMT
// Content-Length: 25

// {"message":"Hello World"}
  • 使用-H来发送报头

响应不同类型的请求

HTTP服务器通常也需要能够响应不同类型的请求。客户端可发出的请求类型是HTTP规范中定义的,包括GET、POST、PUT和DELETE

package main

import (
    "net/http"
)

func hello(w http.ResponseWriter,r *http.Request){
    if r.URL.Path != "/"{
        http.NotFound(w,r)
        return
    }
    switch r.Method{
    case "GET":
        w.Write([]byte("Received a GET"))
    case "POST":
        w.Write([]byte("Received a POST"))
    default:
        w.WriteHeader(http.StatusNotImplemented)
        w.Write([]byte("error"))
    }
}

func main(){
    http.HandleFunc("/",hello)
    http.ListenAndServe(":8000",nil)

}

// $ curl -is http://127.0.0.1:8000 -X POST
// HTTP/1.1 200 OK
// Date: Thu, 28 Jan 2021 15:18:24 GMT
// Content-Length: 15
// Content-Type: text/plain; charset=utf-8

// Received a POST
// Administrator@PC-202101161235 MINGW64 ~
// $ curl -is http://127.0.0.1:8000 -X GET
// HTTP/1.1 200 OK
// Date: Thu, 28 Jan 2021 15:18:34 GMT
// Content-Length: 14
// Content-Type: text/plain; charset=utf-8

// Received a GET
  • 可以使用-X选项来指定请求的类型

获取GET和POST请求中的数据

HTTP客户端可在HTTP请求中向HTTP服务器发送数据,这样的典型实例包含以下几点:

  • 提交表单
  • 设置有关要返回的数据的选项
  • 通过API管理数据

读取URL中GET请求的数据

func queryParams(w http.ResponseWriter,r *http.Request){
    for k,v := range r.URL.Query(){
        fmt.Printf("%s : %s \n",k,v)
    }
}

在POST请求中,数据通常是在请求体中发送的。要读取并使用这些数据,可像下面这样做

func queryParams(w http.ResponseWriter,r *http.Request){
    reqBody,err := ioutil.ReadAll(r.Body)
    if err != nil{
        log.Fatal(err)
    }
    fmt.Printf("%s",reqBody)
}

下面是一个实例

package main

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

func hello(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(){
            w.Write([]byte(string(k)+":"+string(v[0])))
            w.Write([]byte("\nGET"))
        }
    case "POST":
        reqBody,err := ioutil.ReadAll(r.Body)
        if err != nil {
            log.Fatal(err)
        }
        w.Write([]byte(reqBody))
        w.Write([]byte("\nPOST"))
    }
}

func main(){
    http.HandleFunc("/",hello)
    http.ListenAndServe(":8000",nil)
}

运行结果:

//发送GET
$ curl -is http://127.0.0.1:8000/?foot=siqu -X GET
HTTP/1.1 200 OK
Date: Thu, 28 Jan 2021 15:45:28 GMT
Content-Length: 13
Content-Type: text/plain; charset=utf-8

foot:siqu
GET
//发送POST
$ curl -is http://127.0.0.1:8000/?foot=siqu -X POST -d "some data to send"
HTTP/1.1 200 OK
Date: Thu, 28 Jan 2021 15:58:25 GMT
Content-Length: 22
Content-Type: text/plain; charset=utf-8

some data to send
POST
© 版权声明
THE END
喜欢就支持以下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容