Web应用

Web应用

Go语言里面提供了一个完善的net/http包,通过http包可以很方便的就搭建起来一个可以运行的Web服务。同时使用这个包能很简单地对Web的路由,静态文件,模版,cookie等进行设置和操作。

package main

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

func sayHelloName(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fmt.Println("path:", r.URL.Path)
	fmt.Fprintf(w, "hello go")
}

func main() {
	http.HandleFunc("/", sayHelloName)
	err := http.ListenAndServe(":9090", nil)

	if err != nil {
		log.Fatal("ListenAndServer: ", err)
	}
}

HTTP包运行机制

Go实现Web服务流程如下

  1. 创建Listen Socket,监听指定的端口,等待客户端请求到来。

  2. Listen Socket 接受客户端的请求,得到Client Socket,接下来通过 Client Socket 与客户端通信。

  3. 处理客户端的请求,首先从 Client Socket 读取HTTP请求,然后交给相应的 handler 处理请求,最后将 handler 处理完毕的数据,通过 Client Socket 写给客户端。

其中涉及服务器端的概念:

  • Request:用户请求的信息,用来解析用户的请求信息,包括post、get、cookie、url等信息
  • Conn:用户的每次请求链接
  • Handler:处理请求和生成返回信息的处理逻辑
  • Response:服务器需要反馈给客户端的信息

服务监听与请求处理过程

Go是通过一个ListenAndServe监听服务,底层处理:初始化一个server对象,然后调用 net.Listen("tcp", addr),监控我们设置的端口。监控端口之后,调用 srv.Serve(net.Listener) 函数,处理接收客户端的请求信息。首先通过Listener接收请求,其次创建一个Conn,最后单独开了一个goroutine,把这个请求的数据当做参数扔给这个conn去服务。go c.serve()用户的每一次请求都是在一个新的goroutine去服务,相互不影响。

分配相应的函数处理请求: conn首先会解析request:c.readRequest(),然后获取相应的handler:handler := c.server.Handler,这个是调用函数ListenAndServe时候的第二个参数,例子传递的是nil,也就是为空,那么默认获取 handler = DefaultServeMux。DefaultServeMux 是一个路由器,它用来匹配url跳转到其相应的handle函数。调用 http.HandleFunc("/", sayhelloName) 作用是注册了请求/的路由规则,将urlhandle函数注册到DefaultServeMux变量,最后调用DefaultServeMuxServeHTTP方法,这个方法内部调用handle函数。

服务监听与请求处理流程图

自定义路由实现

定义的类型实现ServeHTTP方法,即可实现自定义路由

package main

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

type MyMux struct {}

func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/" {
        sayhelloName(w, r)
        return
    }

    http.NotFound(w, r)
    return
}


func sayhelloName(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    fmt.Println("path:", r.URL.Path)
    fmt.Fprintf(w, "hello go")
}

func main() {
    mux := &MyMux{}
    err := http.ListenAndServe(":9090", mux)
    if err != nil {
        log.Fatal("ListenAndServer: ", err)
    }
}