net/http包简介 | 豆包MarsCode AI刷题

112 阅读3分钟

GO网络编程包net/http

net/http包提供了HTTP客户端和服务器的实现。

hello world

通过http.HandleFunc()http.ListenAndServe()两个函数就可以轻松创建一个简单的Go web服务器,示例代码如下:

 package main
 ​
 import (
     "fmt"
     "net/http"
 )
 ​
 func hello(w http.ResponseWriter, r *http.Request) {
     fmt.Fprintf(w, "Hello!")
 }
 ​
 func main() {
     http.HandleFunc("/hello", hello)
     http.ListenAndServe(":8080", nil)
 }

其中*http.Request表示 HTTP 请求对象,该对象包含请求的所有信息,如 URL、首部、表单内容、请求的其他内容等。http.ResponseWriter是一个接口类型:

type ResponseWriter interface 
{   Header() Header   Write([]byte) (int, error)   WriteHeader(statusCode int) } 

用于向客户端发送响应,实现了ResponseWriter接口的类型显然也实现了io.Writer接口。所以在处理函数index中,可以调用fmt.Fprintln()ResponseWriter写入响应信息。

Server结构体

Server结构体代表一个HTTP服务器。这个结构体包含了若干配置选项,可以用来自定义服务器的行为。

type Server struct {
    Addr           string        // HTTP服务器监听的地址
   Handler        Handler       // 处理所有HTTP请求的处理器,Handler:nil表明服务器使用默认的多路复用器DefaultServeMux
    TLSConfig     *tls.Config   // 用于TLS握手的配置
    ReadTimeout   time.Duration // 读取客户端请求的时间限制
    WriteTimeout  time.Duration // 写入客户端响应的时间限制
    IdleTimeout   time.Duration // 连接空闲超时时间
    MaxHeaderBytes int          // 请求头部的最大字节数
    ...
}

对应的方法:

func (srv *Server) ListenAndServe() error

ListenAndServe:启动服务器监听并服务HTTP请求。这个方法会阻塞调用者,直到服务器停止或发生错误。

路由注册方案

  1. 事件处理器的Handler接口定义如下,只要实现了这个接口,就可以实现自己的handler处理器。
 type Handler interface {
     ServeHTTP(ResponseWriter, *Request)
 }

使用Handler接口进行路由注册,将URL路径与handler关联起来:

package main

import (
    "fmt"
    "net/http"
)

// MyHandler 结构体
type MyHandler struct{}

// ServeHTTP 方法,使得 MyHandler 实现了 http.Handler 接口
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, you've hit the home page!")
}

func main() {
    // 创建 MyHandler 的实例
    handler := MyHandler{}

    // 使用 http.Handle 注册 handler 到默认的 ServeMux
    http.Handle("/", &handler)

    // 启动服务器
    if err := http.ListenAndServe(":8080", nil); err != nil {
        panic(err)
    }
}

实现handler接口还可以使用适配器HandlerFunc,允许一个普通函数满足http.Handler接口。这样,你可以直接使用函数作为HTTP处理器,而不需要创建一个结构体并实现ServeHTTP方法。 其源码为:

 type HandlerFunc func(ResponseWriter, *Request)
 ​
 // ServeHTTP calls f(w, r).
 func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
     f(w, r)
 }

可以这样使用HandlerFunc

var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, world!"))
})
  1. 使用http.HandleFunc函数,允许使用普通函数作为http.Handler。如果有一个函数签名为func(ResponseWriter, *Request),可以直接用这个函数作为handler,而不需要专门实现http.Handler接口。将一个URL模式和对应的HandlerFunc关联起来,并注册到默认的ServeMux
package main

import (
    "fmt"
    "net/http"
)

func main() {
    // 使用 http.HandleFunc 注册一个函数作为 handler 到默认的 ServeMux
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello, you've hit the home page!")
    })

    // 启动服务器
    if err := http.ListenAndServe(":8080", nil); err != nil {
        panic(err)
    }
}

多路复用器

ServeMux:根据请求的URL地址找到对应的处理器,调用处理器对应的ServeHTTP()方法处理请求。 DefaultServeMux是net/http包的默认多路复用器,其实就是ServeMux的一个实例。

HandleFunc()处理器函数会在内部调用DefaultServeMux对象对应的方法,其内部实现:

 // HandleFunc registers the handler function for the given pattern
 // in the DefaultServeMux.
 // The documentation for ServeMux explains how patterns are matched.
 func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
     DefaultServeMux.HandleFunc(pattern, handler)
 }

http.Handle()函数可以调用DefaultServeMux.Handle()方法来处理请求。

 func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

自定义多路复用器

虽然默认的多路复用器很好用,但仍然不推荐使用,因为它是一个全局变量,所有的代码都可以修改它。有些第三方库中可能与默认复用器产生冲突。所以推荐的做法是自定义。

package main
 ​
 import (
     "fmt"
     "net/http"
 )
 ​
 func newservemux(w http.ResponseWriter, r *http.Request) {
     fmt.Fprintf(w, "NewServeMux")
 }
 ​
 func newservemuxhappy(w http.ResponseWriter, r *http.Request) {
     fmt.Fprintf(w, "Newservemuxhappy")
 }
 ​
 func newservemuxbad(w http.ResponseWriter, r *http.Request) {
     fmt.Fprintf(w, "NewServeMuxbad")
 }
 func main() {
     mux := http.NewServeMux()
     mux.HandleFunc("/", newservemux)
     mux.HandleFunc("/happy", newservemuxhappy)
     mux.HandleFunc("/bad", newservemuxbad)
     s := &http.Server{
         Addr:    ":8080",
         Handler: mux,
     }
 ​
     s.ListenAndServe()
 }