虽然我个人不太喜欢RESTful的接口命名风格,但无可否认,RESTful已成为一种逐渐为大众所接受并使用的方式,下面来说下怎么在动态路由的情况下支持RESTful
要支持RESTful,其实就是根椐请求的方法(GET,POST,PUT,DELETE等)和path,自动路由至相应的controller方法,例如:
- GET /User/xxx -> func(this *App) GETUser(){}
- POST /User/xxx/Task -> func(this *App) POSTUserTask(){}
由此可以看出,实际上就是对METHOD和PATH进行分拆合并生成方法名和相关参数,然后用反射方式调用相应的方法,如果方法不存在,报404(或者更友好的提示页)
dispatch
path := strings.Split(r.URL.Path, "/")if path[1] == "" { //welcome page return} else { var name []byte var params []string for l, i := len(path), 1; i < l; i++ { //path的格式是 /object/id/object/id... if i%2 != 0 { name = append(name, []byte(strings.Title(path[i]))...) } else { params = append(params, path[i]) } } app.pathParams = params //将参数放到controler的reciver的属性中 controlName := r.Method + string(name) //根椐method和path中object部分,串接出controlName //调用方法 method, exist := rType.MethodByName(controlName) if exist { args := []reflect.Value{rValue} method.Func.Call(args) } else { //404 not found }}
controller
// GET /User/xxx 时调用func (this *App) GETUser() { fmt.Fprintf(this.w, "Get /User/xx: params=%s", this.pathParams)}// GET /User/xxx/Task/xxx 时调用func (this *App) GETUserTask() { fmt.Fprintf(this.w, "Get /User/xxx/Task/xxx :params=%s", this.pathParams)}