前言:此框架的请求处理主要是依赖于Golang中的net/http包
http.ListenAndServe 方法的使用
实现http简单服务示例:参考文档 https://studygolang.com/pkgdoc
示例1
http.Handle("/foo", fooHandler) http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) }) log.Fatal(http.ListenAndServe(":8080", nil))
- 示例2:
s := &http.Server{ Addr: ":8080", Handler: myHandler, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } log.Fatal(s.ListenAndServe())
- 本框架的处理思路:
- 从http包看,http.ListenAndServe(":8080", nil) 这个方法的第二个参数是http.Handler对象,而这个对象是一个接口,所以要实现ServeHttp方法
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
- 在core包下面声明了一个Application对象,这个对象实现了 ServeHTTP 方法,在这个方法里面进行路由的判断,然后根据取到的路由找到 控制器和对应的方法,最后在协程里面利用反射调用 对用的控制器的相应的方法从而得到调用方法的结果(这个结果指的是方法调用成功或者失败之类的结果)。在执行调用方法的过程中,http请求的参数通过 ServeHTTP的 *Request对象获取,http的响应的结果可以通过 fmt.Fprint(ResponseWriter对象, "响应结果字符串")。
注:关于请求参数的获取以及响应结果的返回,在之后的博客中会详细讲到。
- 框架入口:public包中的main.go
func main() { routers := route.GetRouter() controllers := route.GetControllers() app := new(core.Application) app.Routers = routers app.Controllers = controllers err := http.ListenAndServe("localhost:8080", app) if err != nil { log.Println("ListenAndServe: ", err) } } }
在这个方法中首先 初始化一个Application对象,然后获取用户注册的路由及控制器,将其作为app对象的属性赋给app对象,然后使用http.ListenAndServe("localhost:8080", app) 。当请求过来的时候就会直接到app的ServeHTTP方法中,然后就会顺着 2 的思路执行。
- 其他处理
- 路由的处理
在这个框架中路由如下:
package route import "goweb/controller" var routers = map[string]string{ // 示例 请求类型@控制器@方法 "/test": "get@TestController@Test", } var controllers = map[string]interface{}{ // 示例 反射中用到 "TestController": &controller.TestController{}, } func GetRouter() map[string]string { return routers } func GetControllers() map[string]interface{} { return controllers }
在1.2.3 中提到了这个框架的路由的使用时 赋值给app对象了,然后再app中进行路由处理。通过routers数组可以获取路由和控制器、方法之间的关系,通过controllers数组获取到对应的控制器的结构体的地址,然后通过反射机制调用对应的控制器的对应方法
- 利用反射调用方法
// 反射调用方法 func CallFuncByName(myClass interface{}, funcName string, params ...interface{}) (out []reflect.Value, err error) { myClassValue := reflect.ValueOf(myClass) m := myClassValue.MethodByName(funcName) if !m.IsValid() { return make([]reflect.Value, 0), fmt.Errorf("Method not found \"%s\"", funcName) } in := make([]reflect.Value, len(params)) for i, param := range params { in[i] = reflect.ValueOf(param) } out = m.Call(in) return out, nil }
反射一般用在知道对象及方法名称,想要得到对象的类或者调用对象的方法的情况。在MVC框架中(根据解析到的路由,动态执行方法)用得比较多一些。
注:1. 本文涉及到的代码的git仓库地址:https://github.com/zhuchenglin/goweb