Go中进行web开发是十分快捷和方便的,因为封装的比较好,并且,由于Go语言天生的并发性,这使得我们开发一个并发性很好的服务端很容易。我也是刚开始学习Go语言,这篇文章就是一个学习笔记,水平很菜,错误之处,还请各位看官指出!
1.最简单的版本:
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/", sayHello)
http.ListenAndServe(":8080", nil)
}
func sayHello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
这个是基本的,有一个小的疑问,就是sayHello函数中的参数,第二个是指针,而第一个不是。查看官网,我们发现,type ResponseWriter interface和type Request struct的区别,结构体当然要用指针,这样的省去复制带来的开销。而接口为什么这样不用指针类型:我的理解是:”如果用指针类型,而实现这个接口的是一个结构的指针的话,这样就是指针的指针,而一般实现接口的都是结构的指针“,当然这个理解可能是错误的。这个程序中首先是用handleFunc()进行路由设置,然后就是监听端口。func HandleFunc(pattern string, handler func(ResponseWriter, *Request))和func ListenAndServe(addr string, handler Handler) error这是二个函数的API,type Handler interface { ServeHTTP(ResponseWriter, *Request) },而listenAndServe这个函数的第二个参数便是一个接口。现在,我们来看看HandleFunc()函数的源码:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
原来这个函数是调用了ServerMux的HandleFunc方法的,
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
HandlerFunc(handler)只是将handler转化成了HandlerFunc类型的了。type HandlerFunc func(ResponseWriter, *Request)这是定义。那么,我们稍微深入一下,试着用Handle函数来做一下。
2.稍微深入:
我们注意到,注册路由的函数还有一个就是func Handle(pattern string, handler Handler),第二个参数是一个接口,这个接口实现ServeHTTP(ResponseWriter, *Request)函数的接口,我们就用这个函数来做一个。
package main
import (
"net/http"
)
type myHandle struct {
}
func main() {
http.Handle("/", &myHandle{})
http.ListenAndServe(":8080", nil)
}
func (*myHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world2"))
}
通过API,我们也注意到,ListenAndServe()函数的第二个参数也是handle接口,那么这个handle是不是也是自定义的实现接口那?不是,通过API的一段”The handler is typically nil, in which case the DefaultServeMux is used.“原来,这儿实现handle接口的结构体已经有规范了,是ServerMux,这个ServerMux是一个什么类型,:
type ServeMux struct { // contains filtered or unexported fields }
是一个结构体,着结构体的意义:”ServeMux是一个HTTP请求多路复用器。它将每个传入请求的URL与已注册模式的列表进行匹配,并调用与URL最匹配的模式的处理程序”。这是API上的简介。那么我们可以通过ServerMux来进行路由注册等操作。可以选择func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))方法进行路由注册。
package main
import (
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", sayHello)
http.ListenAndServe(":8080", mux)
}
func sayHello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world3"))
}
上面,已经用Handle函数实现了。再看看Handle函数的源码:
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
mux.m[pattern] = muxEntry{h: handler, pattern: pattern}
if pattern[0] != '/' {
mux.hosts = true
}
}
我们发现它是利用ServeMux结构来操作的,
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
explicit bool
h Handler
pattern string
}
其实,我们也可以通过自己定义一个map实现这种匹配:
3.稍微再深入:
现在进行自定义server,server的API上的定义:
type Server struct {
Addr string // TCP address to listen on, ":http" if empty
Handler Handler // handler to invoke, http.DefaultServeMux if nil
TLSConfig *tls.Config
ReadTimeout time.Duration
ReadHeaderTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
MaxHeaderBytes int
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
ConnState func(net.Conn, ConnState)
ErrorLog *log.Logger
}
这种形式的代码如下:
package main
import (
"net/http"
"time"
)
var mux map[string]func(http.ResponseWriter, *http.Request)
func main() {
server := http.Server{
Addr: ":8080",
Handler: &myHandle{},
ReadTimeout: 10 * time.Second,
}
mux = make(map[string]func(http.ResponseWriter, *http.Request))
mux["/hello"] = sayHello
server.ListenAndServe()
}
type myHandle struct{}
func (*myHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if h, ok := mux[r.URL.String()]; ok {
h(w, r)
return
}
w.Write([]byte("others"))
}
func sayHello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world 4"))
}
代码比较简单,也没什么可以解释的。
以上的三种形式的web简单代码,如有错误,还请指正!声明:以上代码,没有进行错误处理,只是简单演示。分享一个关于Go语言方便的API查询网站:https://gowalker.org/net/http#Server