net/http
Go 已经拥有成熟的 HTTP 标准库 net/http
,即使不使用 Go 的 Web 框架如 Gin、Iris 等也可以快速的搭建起一个可以运行的 Web 服务,同时这个标准库可以对 Web 路由、静态文件、模板和cookie 等数据进行处理,事实上这些 Web 框架也都是基于 net/http
标准库来构建的。
net/http
建立 Web 服务器首先创建一个请求处理函数 sayHelloHandler
,该函数接收一个 http.ResponseWriter
和 一个请求指针 *http.Request
作为参数,通过对请求中数据的提取之后写入指定的信息到 http.ResponseWriter
中。
在 main 函数中通过 http.HandleFunc
定义一个路由并将该路由与 sayHelloHandler
函数映射,然后通过 http.ListenAndServe
监听端口。
运行 main.go 文件,一个简单的 Web 服务器就运行起来了。
package main
// filename main.go
//noinspection ALL
import (
"fmt"
"log"
"net/http"
"strings"
)
//noinspection ALL
func main(){
http.HandleFunc("/", sayHelloName)
err := http.ListenAndServe(":9000", nil)
if err != nil {
log.Fatal("ListenAndServer: ", err)
}
}
func sayHelloHandler(w http.ResponseWriter, r *http.Request){
r.ParseForm() // 解析参数,默认是不会解析的
fmt.Println(r.Form) // 输出
fmt.Println("path", r.URL.Path)
fmt.Print("Scheme", r.URL.Scheme)
fmt.Println(r.Form["url_long"])
for k, v := range r.Form{
fmt.Println("Key", k)
fmt.Println("Val", strings.Join(v, ""))
}
fmt.Fprint(w, "Hello, Go HTTP")
}
在浏览器中输入 http://localhost:9000/
控制台打印出的详细信息
net/http
运行机制net/http
运行流程:
整个过程我们需要了解三个问题:
net/http
是如何监听端口的?net/http
是如何接收客户端请求的?net/http
是如何分配 handler 的?查看源码,点击 main.go 文件中 http.ListenAndServe(":9000", nil)
的 ListenAndServe 函数,来到源码,再次点击 3222 行的 ListenAndServe,
再次点击 2968 行的 Serve 函数:
Serve(l net.Listener) 函数就是处理接收客户端的请求信息。该函数中的 for 循环首先通过 net.Listener 接收请求 rw, err := l.Accept()
,for 循环之后又创建了一个 Conn,最后单独开了一个 goroutine go c.serve(connCtx)
;用户的每一次请求都是在一个单独的 goroutine 中执行的,不会相互影响。
点击 go c.serve(connCtx)
中的 serve(connCtx)
方法,在该方法中的第 1891 行通过 c.readRequest(ctx)
来解析请求:
然后在第 1966 行,根据请求解析结果通过 serverHandler{c.server}.ServeHTTP(w, w.req)
分配了一个 handler:
点击查看 ServeHTTP 源码:
这里获取了一个 handler,调用 ListenAndServe 函数的时候传递的参数为 nil,因此这里默认分配了一个 DefaultServeMux 作为 handler。其实 DefaultServeMux 就是一个路由器,它用来匹配 URL 跳转到其响应的 handler 函数。
上述代码中 http.HandleFunc("/", sayHelloName)
就已经定义了路由规则,当请求为 /
时,路由就会转到 sayHelloName 方法,DefaultServeMux 就会调用 ServeHTTP 方法,则这个方法内部其实就是调用 sayHelloName 方法,然后将返回结果写入到 response 中,最后返回给客户端。
整个处理流程如下: