Go语言动手写Web框架学习笔记-第一天
go中的http.ListenAndServe方法
https://www.jianshu.com/p/6b77ada03487
https://blog.csdn.net/JunChow520/article/details/122231734
一、原生http库的http请求代码
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", indexHandler)
http.HandleFunc("/hello", helloHandler)
log.Fatal(http.ListenAndServe(":9999", nil))
}
// handler echoes r.URL.Path
func indexHandler(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
}
// handler echoes r.URL.Header
func helloHandler(w http.ResponseWriter, req *http.Request) {
for k, v := range req.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
}
简化实现handle接口ServerHTTP方法代码解读
https://github.com/geektutu/7days-golang/blob/master/gee-web/day1-http-base/base2/main.go
实现自已的处理器
调用关系 http.ListenAndServer(":9999",engine) -- > engine 是handle接口
http.ListenAndServe(":9999", engine)
这个函数第二个参数engine是处理器,它需要实现http.handle的接口,接口的方法又是
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
所以当你要实现自已的处理器就必须实现handle接口的ServerHttp方法
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
switch req.URL.Path {
case "/":
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
case "/hello":
for k, v := range req.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
default:
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
}
}
这边初版的方法是比较简单的,直接写死,根据req.URL.Path接收到的条件进行做相应的case 处理
更灵活的处理器
首先有以下几个问题要解决
- 可存府注册请求接口pattern和handler的关系
- 可灵活注册请求接口和函数的关系
- 可查找和返回接口和函数的关系
开始看源码
源码地址:https://github.com/geektutu/7days-golang/blob/master/gee-web/day1-http-base/base3/gee/gee.go
import (
"fmt"
"log"
"net/http"
)
//用type 简化匿名函数
// HandlerFunc defines the request handler used by gee
type HandlerFunc func(http.ResponseWriter, *http.Request)
// engine实体数据对象,这个要用来存储pattern和handler.pattern请求接口和handle映射函数
// Engine implement the interface of ServeHTTP
type Engine struct {
router map[string]HandlerFunc
}
//初始化engine,为什么要返回指针,应该是本来方便addRoute
// New is the constructor of gee.Engine
func New() *Engine {
return &Engine{router: make(map[string]HandlerFunc)}
}
//存储请求pattern和handler关系
func (engine *Engine) addRoute(method string, pattern string, handler HandlerFunc) {
key := method + "-" + pattern
log.Printf("Route %4s - %s", method, pattern)
engine.router[key] = handler
}
//这个算是注册pattern和handle最终调用addroute去存到engine.router里
// GET defines the method to add GET request
func (engine *Engine) GET(pattern string, handler HandlerFunc) {
engine.addRoute("GET", pattern, handler)
}
//这个算是注册pattern和handle最终调用addroute去存到engine.router里
// POST defines the method to add POST request
func (engine *Engine) POST(pattern string, handler HandlerFunc) {
engine.addRoute("POST", pattern, handler)
}
//启动服务
// Run defines the method to start a http server
func (engine *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, engine)
}
//实现handle接口具体的处理接口
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
key := req.Method + "-" + req.URL.Path
if handler, ok := engine.router[key]; ok {
handler(w, req)
} else {
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
}
}
总结
参考源码1,任何一个请求抽象到底层就是io,i为进,o为出,在这里是req和response
那么如果我们有一台服务器需要接到不同的请求(用/urls来区分),那就必面为每一个urls都设定一个处理io流,接收和回应
所以就有了http.HandleFunc("/", indexHandler)这样的映射参数,前者为pattern,后者为handler函数。