go web programming - Routing and http service

This article explains the basic principles of routing and service go http web programming language.

First, go the easiest language to start a service http:

package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", sayHello)
	log.Println("server running...")
	log.Fatal(http.ListenAndServe("localhost:4000", nil))
}

func sayHello(writer http.ResponseWriter, req *http.Request) {
	writer.Write([]byte("hello world!"))
}

Compile and run the browser to access http: // localhost: 4000 /, output hello world!.
Overall, this code just to do two things, first, registration routing, specify the path to a client request response function:
http.HandleFunc ( "/", sayHello)
Second, start the http service, listening port receiving and responding to client requests:
http.ListenAndServe ( "localhost: 4000", nil)

 

Look at the first thing - registered route specified path corresponding to the request response function.
First look http.HandleFunc () function Source:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

DefaultServeMux which is the default router go, so routing is actually registered by the router, http.HandleFunc () function simply encapsulates it, then the structure of the router is kind of how it?
Source Visible:

type ServeMux struct {
	mu    sync.RWMutex
	m     map[string]muxEntry
	es    []muxEntry
	hosts bool
}
type muxEntry struct {
	h       Handler
	pattern string
}

Wherein ServeMux structure map [string] muxEntry request is used to save the mapping between the path and the response function. MuxEntry seen from the structure defined, the type of response function for the Handler, the Handler is actually an interface type, source code is as follows:

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

所以,响应函数需要实现这个接口,才能进行路由注册。
源码中声明了一个 HandlerFunc 类型,就实现了 Handler 接口:

type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}

所以,只要我们的响应函数满足结构 func (http.ResponseWriter, *http.Request) ,即可进行路由注册,注册路由时,路由器会将其类型强制转换为 HandlerFunc 。其中,http.ResponseWriter参数包含了响应头、响应数据等响应相关信息,而http.Request参数则包含了请求头、请求参数等请求相关信息。

 

再看第二件事情,启动http服务,监听端口,接受并响应客户端请求。
首先看 http.ListenAndServe() 函数源码:

func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}

其中 Server 即为http服务器类型,其结构如下(省略了部分字段):

type Server struct {
	Addr    string
	Handler Handler
......
}

其中 Addr 为服务器监听的ip与端口字符串,Handler 为路由器,指定其为 nil 时,go会使用它的默认路由器 DefaultServeMux (调用 http.HandleFunc() 方法注册路由时就是注册到这个默认的路由器)。
服务器监听端口,接受客户端请求,并做出响应,这个过程可借助《go web编程》中的一张图示来帮助理解:

图中有两个红色矩形标记,第一个,说明针对客户端的每一个请求,go都会使用一个Goroutine进行响应,保证每个请求都能独立,相互不会阻塞,可以高效响应网络事件;第二,最终调用默认路由器的 ServeHTTP(w ResponseWriter, r *Request) 方法进行路由,从请求路径与响应函数的映射中找到对应的handler,最后调用handler的 ServeHTTP(w ResponseWriter, r *Request) 方法,从上面 HandlerFunc 类型的 ServeHTTP(w ResponseWriter, r *Request) 方法可知,其实最后调用的就是我们注册路由时定义的响应函数本身。

使用go默认路由器的不足之处是,不满足RESTful规则,而且对请求路径的路由只支持绝对匹配,不支持正则匹配。如果想设计一些特殊、简便的路由,需要设计一个自定义路由器,并让go的http服务器使用这个自定义路由器。关于自定义路由器的设计,可以参考笔者另一篇博文:

 

 

借鉴:
《Go Web编程》

 

Guess you like

Origin www.cnblogs.com/wujuntian/p/11858632.html