编写GO的WEB开发框架(三): 如何进行动态路由
2016-03-04 00:00
441 查看
摘要: 对比PHP的常见解决方案,讲述GO如何通过反射方式实现根椐PATH等进行动态规则路由的方法
大部份情况下,开发者并不想每写一个Controller,还要去改写一下路由表,因为这样的话,Controller一多,维护路由表并不是一件讨好的事件。
较好的解决方案是直接由请求的路径(或请求参数)来动态分派到相应的控制器方法,习惯地,这种方式称为动态路由或规则路由,一个明显的特征是自动进行请求路径与控制器方法的匹配。
比如:
请求 /User 表示调用名字为User的Controller方法
请求 /Task 表示调用名字为Task的Controller方法
如果对应的方法不存在,则响应404
(如果需要区分请求方法来作不同的处理,在Controller方法中实现)
实际使用时,由于应用与框架不属于同一个包,控制器的reciver肯定不能是框架内的App结构实例(go不能使用别的包的结构来作为reciver):
这个时候,http.HandleFunc内的实现方式是:
根椐固定的请求参数 c=xxx
根椐某个指定Header
根椐Cookie
关于如何支持RESTful,将在下篇讲述。
本篇示例代码只是演示动态路由的实现,没有考虑安全和其它因素
大部份情况下,开发者并不想每写一个Controller,还要去改写一下路由表,因为这样的话,Controller一多,维护路由表并不是一件讨好的事件。
较好的解决方案是直接由请求的路径(或请求参数)来动态分派到相应的控制器方法,习惯地,这种方式称为动态路由或规则路由,一个明显的特征是自动进行请求路径与控制器方法的匹配。
比如:
请求 /User 表示调用名字为User的Controller方法
请求 /Task 表示调用名字为Task的Controller方法
如果对应的方法不存在,则响应404
(如果需要区分请求方法来作不同的处理,在Controller方法中实现)
在php的实现
常见方式是根椐请求的路径或参数,直接include相应的controller类,然后在new一下就可以:<?php $controller = $_GET['c]; $method = $_GET['m']; $file = "{$controller}_control.php"; file_exists($file) && include $file; //如果class或method不存在,输出404 $c = new $controller; $c -> $method(); ?>
在GO中实现
由于go是静态语言,不能动态载入,只能通过反射来解决:package main import ( "fmt" "log" "net/http" "reflect" "strings" ) type App struct { w http.ResponseWriter } func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/public/") { //匹配静态文件服务 } else { app := &App{w} rValue := reflect.ValueOf(app) rType := reflect.TypeOf(app) path := strings.Split(r.URL.Path, "/") controlName = path[1] method, exist := rType.MethodByName(controlName) if exist { args := []reflect.Value{rValue} method.Func.Call(args) } else { fmt.Fprintf(w, "method %s not found", r.URL.Path) } } }) log.Fatal(http.ListenAndServe("localhost:8080", nil)) } //控制器 func (this *App) Say() { fmt.Fprintf(this.w, "Say called") }
实际使用时,由于应用与框架不属于同一个包,控制器的reciver肯定不能是框架内的App结构实例(go不能使用别的包的结构来作为reciver):
package controller import "framework" type Controller struct{ *framework.App //controller其它属性 } func (this *Controller) Say({ //可以直接调用framework.App提供的方法和属性 }
这个时候,http.HandleFunc内的实现方式是:
app := controller.Controller{} rValue := reflect.ValueOf(app) rType := reflect.TypeOf(app) reciver := rValue.Elem().FieldByName("App") reciver.Set(reflect.ValueOf(&App{w})) //设置controller.Controller的匿名字段App method, exist := rType.MethodByName(controlName) if exist { args := []reflect.Value{rValue} method.Func.Call(args) }else{ //404 }
路径分配策略
上述示例代码是直接使用Path的第一段来dispatch,如有需要,可有更多的方式,比如:根椐固定的请求参数 c=xxx
根椐某个指定Header
根椐Cookie
关于如何支持RESTful,将在下篇讲述。
本篇示例代码只是演示动态路由的实现,没有考虑安全和其它因素
相关文章推荐
- node.js Web应用框架Express入门指南
- python常用web框架简单性能测试结果分享(包含django、flask、bottle、tornado)
- 高性能web服务器框架Tornado简单实现restful接口及开发实例
- Python Web框架Pylons中使用MongoDB的例子
- [续] 懒到极致:对mybatis的进一步精简
- Python 17.4 使用Web框架
- RIP-上
- 类似于AngularJS HTML的Web框架——jsui
- iOS 并发编程(1)
- iOS 并发编程(2)
- WebWork深入浅出 (转贴)http://www.blogjava.net/moxie/archive/2006/10/20/76375.html
- Yii源码分析——1、简介
- 起点
- 创建单例
- Spring 7大功能模块的作用
- FastJsp3.1正式开源,欢迎使用。
- 下一代的B/S开发框架--Echo 教程(6)
- Spring集成其他Web框架
- Spring Framework
- 如何选择Web框架