-
Notifications
You must be signed in to change notification settings - Fork 0
Description
我们首先来写一个最简单的 Web 服务器,代码仅仅调用了 http.ListenAndServe 函数
package main
import "net/http"
func main() {
http.ListenAndServe(":8080", nil)
}http.Server
我们也可以创建一个 http.Server 对象,调用其 ListenAndServe 方法来开启 Web 服务器,这两种方式是等价的
package main
import "net/http"
func main() {
server := http.Server{
Addr: ":8080",
Handler: nil,
}
server.ListenAndServe()
}实质上 http.ListenAndServe 函数只是一个语法糖,在内部就是创建了 http.Server 和调用其 ListenAndServe 方法
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}当不需要太多配置时,可以使用该函数,而想更多的自定义配置的话,就手动创建 http.Server,其定义如下
type Server struct {
Addr string
Handler Handler
ReadTimeout time.Duration
ReadHeaderTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
MaxHeaderBytes int
TLSConfig *tls.Config
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
ConnState func(net.Conn, ConnState)
ErrorLog *log.Logger
}创建 http.Server 最重要的两个参数是 Addr 和 Handler
但是上面调用 http.ListenAndServe 函数或是创建 http.Server 时,都将 Handler 设置为了 nil
当 Handler 为 nil 时,服务器会使用默认的多路复用器 DefaultServeMux
多路复用器之后再说,我们先来创建自己的处理器
http.Handler
Handler 是一个接口,定义如下
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}因此我们只要创建一个结构体,实现 ServeHTTP(ResponseWriter, *Request) 方法即可,该方法用来处理 HTTP 请求,代码如下
package main
import (
"fmt"
"net/http"
)
type MyHandler struct {}
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
handler := &MyHandler{}
server := http.Server{
Addr: "127.0.0.1:8080",
Handler: handler,
}
server.ListenAndServe()
}http.Request
http.Request 是一个结构体,保存了请求相关的各种信息
Web 编程中经常要获取的 URL 信息,Header 信息,表单信息就通过该参数获取
type Request struct {
Method string
URL *url.URL
Proto
ProtoMajor int
ProtoMinor int
Header Header
Body io.ReadCloser
GetBody func() (io.ReadCloser, error)
ContentLength int64
TransferEncoding []string
Close bool
Host string
Form url.Values
PostForm url.Values
MultipartForm *multipart.Form
Trailer Header
RemoteAddr string
RequestURI string
TLS *tls.ConnectionState
Cancel <-chan struct{}
Response *Response
} 获取指定 Header 字段的值
r.Header["Accept-Encoding"] // 返回 []string, eg: ["gzip", "deflate", "br"]
r.Header.Get("Accept-Encoding") // 返回 string, eg: "gzip, deflate, br"http.ResponseWriter
http.ResponseWriter 是一个接口,用来向 HTTP 响应报文的 Body 写入数据
type ResponseWriter interface {
Write([]byte) (int, error)
Header() Header
WriteHeader(statusCode int)
}输出 Hello World 的方法有三种,如下
w.Write([]byte("Hello World"))
fmt.Fprintf(w, "Hello World")
io.WriteString(w, "Hello World")第一种不必说,直接调用 Write 方法,但这里需要将 string 转换成 byte[]
剩下两种方法其实都在内部使用了 Write 方法,如下
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
n, err = w.Write(p.buf)
p.free()
return
}func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s)
}
return w.Write([]byte(s))
}这里两个函数接收的参数是 io.Writer 类型,该类型是一个接口,如下
type Writer interface {
Write(p []byte) (n int, err error)
}而 http.ResponseWriter 接口也定义了相同的 Write 方法,所以实现了 http.ResponseWriter 接口的类型,必定也实现了 io.Writer 接口,因此可以使用上述两个函数
http.ServeMux
我们现在开启了一个 HTTP 服务器,然后写了一个 Handler 来处理 HTTP 请求,向页面输出 Hello World
但这远远不够,至少我们要能对不同的 URL 调用不同的函数去处理,我们需要路由功能
多路复用器 http.ServeMux 就提供了这样的功能,它负责接收 HTTP 请求并根据请求中的 URL 来重定向到正确的 Handler
当然,http.ServeMux 本身也是一个 Handler,实现了 ServeHTTP 方法,其定义及方法如下
type ServeMux struct {}
func NewServeMux() *ServeMux
func (mux *ServeMux) Handle(pattern string, handler Handler)
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)接下来我们创建两个 Handler,并使用默认的多路复用器分发请求到两个处理器
package main
import (
"fmt"
"net/http"
)
type FooHandler struct {}
type BarHandler struct {}
func (h *FooHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "foo")
}
func (h *BarHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "bar")
}
func main() {
foo := &FooHandler{}
bar := &BarHandler{}
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.Handle("/foo", foo)
http.Handle("/bar", bar)
server.ListenAndServe()
}