Los componentes HTTP HTTP de enrutamiento de solicitud del proceso entregado función (o un método struct) correspondientes, tal como se describe en la estructura de la sección anterior, en el marco corresponde a un controlador de eventos de enrutamiento, y el evento comprende:
- El usuario solicita una ruta(path)( e.g.:/user/123,/article/123), por supuesto, el string de consulta(e.g., ? Id = 11)
- HTTP Método de solicitud(method)(GET, POST, PUT, DELETE, PATCH, etc. )
El router se basa en la petición del usuario se envía a la función de procesamiento de información de evento respectivo (capa de control).
Se han introducido en el apartado 3.4 del paquete http Go detallada, que introdujo el paquete http del Go cómo diseñar e implementar el enrutamiento, aquí seguirá siendo un ejemplo para ilustrar:
func fooHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}
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))
El ejemplo anterior llama al http predeterminado DefaultServeMux agregar una ruta, es necesario proporcionar dos parámetros, el primer parámetro es el recurso que desea que los usuarios tengan acceso a la ruta de acceso URL (almacenado en r.URL.Path), el segundo argumento está a punto de ser función ejecutada para proporcionar al usuario el acceso a los recursos. Routing se centró principalmente en dos ideas:
- Añadir información de enrutamiento
- De acuerdo con la solicitud del usuario se reenvía a la función a realizar
Go añade la ruta por defecto través de una función http.Handle y http.HandleFunc , etc. añade, al llamar a DefaultServeMux.Handle(pattern string, handler Handler)
, esta función se establece de la información de enrutamiento se almacena en un map de información en map [string] muxEntry
, que se ocuparía de lo anterior dicho primer punto.
Go escucha en el puerto, y luego recibe la conexión tcp arrojado Handler para proceso, el ejemplo anterior es el valor predeterminado nil http.DefaultServeMux
, DefaultServeMux.ServeHTTP
por la función de programación, el map de ruta de travesía información previamente almacenada y la dirección URL de usuario coincidente visitada para comprobar el controlador registrado correspondiente, para lograr el segundo punto arriba mencionado.
for k, v := range mux.m {
if !pathMatch(k, path) {
continue
}
if h == nil || len(k) > n {
n = len(k)
h = v.h
}
}
Casi todas las aplicaciones web se basan enrutamiento para lograr enrutador http por defecto, pero el router que viene en Go tiene varias limitaciones:
-
No es compatible con el ajuste de parámetros, tales como / user /: uid Este tipo bandeja a juego
-
No muy buen soporte para el modo REST, no se puede restringir los métodos de acceso, como el ejemplo anterior, el acceso de usuarios / foo, puede utilizar GET, POST, DELETE, HEAD, etc Acceso
-
Reglas de enrutamiento sitio Generales demasiado, escribir engorroso. Estoy delante de una API para desarrollar sus propias aplicaciones, las reglas de enrutamiento tienen treinta varios, de hecho, esta ruta después de más que se puede simplificar aún más mediante un método simplificado de la estructura
Los routers del framework beego basados en las pocas limitaciones anteriores a considerar el diseño de un enfoque REST para lograr el enrutamiento, diseño de enrutamiento se basa en dos puntos por encima del diseño por defecto Ir a considerar: el enrutamiento de enrutamiento store-and-forward
Para el punto de restricción se ha mencionado anteriormente, debemos resolver primero los argumentos que apoyan la necesidad de utilizar el punto regular, segundo y tercero pasamos una alternativa viable para resolver, el método REST corresponde a un método struct ir, y luego derrotó a la estructura en lugar de una función, de modo que cuando el método de enrutamiento hacia adelante se puede realizar de acuerdo con diferentes métodos.
Sobre la base de las ideas anteriores, se diseñaron dos tipos de datos controllerInfo (salvo ruta de acceso y la estructura correspondiente, aquí es un tipo reflect.Type) y ControllerRegistor (routers se utilizan para guardar el usuario añadir un slice de información de enrutamiento, y la aplicación del marco beego información)
type controllerInfo struct {
regex *regexp.Regexp
params map[int]string
controllerType reflect.Type
}
type ControllerRegistor struct {
routers []*controllerInfo
Application *App
}
función de interfaz externa tiene
func(p *ControllerRegistor) Add(pattern string, c ControllerInterface)
Implementación detallado es el siguiente:
func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) {
parts := strings.Split(pattern, "/")
j := 0
params := make(map[int]string)
for i, part := range parts {
if strings.HasPrefix(part, ":") {
expr := "([^/]+)"
//El usuario puede optar por invalidar la expresión defult
// similar a expressjs: ‘/user/:id([0-9]+)’
if index := strings.Index(part, "("); index != -1 {
expr = part[index:]
part = part[:index]
}
params[j] = part
parts[i] = expr
j++
}
}
//Crear el patrón de url, con parámetros reemplazados
//Por expresiones regulares. a continuación, compilar la expresión regular
pattern = strings.Join(parts, "/")
regex, regexErr := regexp.Compile(pattern)
if regexErr != nil {
//TODO add error handling here to avoid panic
panic(regexErr)
return
}
//now create the Route
t := reflect.Indirect(reflect.ValueOf(c)).Type()
route := &controllerInfo{}
route.regex = regex
route.params = params
route.controllerType = t
p.routers = append(p.routers, route)
}
El enrutamiento estático
Por encima de que logremos la realización de enrutamiento dinámico, el paquete http de Go apoyada por defecto estática handler FileServer, ya que hemos implementado un enrutador personalizado, a continuación, los archivos estáticos también tienen que establecer su propia, ruta de la carpeta estaica en beego donde se almacena la variable global StaticDir , StaticDir es un tipo de mapa de lograr lo siguiente:following:
func (app *App) SetStaticPath(url string, path string) *App {
StaticDir[url] = path
return app
}
Las aplicaciones pueden utilizar la ruta estática se ajusta para alcanzar la siguiente manera:
beego.SetStaticPath("/img", "/static/img")
Reenvío de ruta en el enrutamiento se basa ControllerRegistor transmisión de información, detalló a alcanzar el siguiente código muestra:
// AutoRoute
func (p *ControllerRegistor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
if !RecoverPanic {
// go back to panic
panic(err)
} else {
Critical("Handler crashed with error", err)
for i := 1; ; i += 1 {
_, file, line, ok := runtime.Caller(i)
if !ok {
break
}
Critical(file, line)
}
}
}
}()
var started bool
for prefix, staticDir := range StaticDir {
if strings.HasPrefix(r.URL.Path, prefix) {
file := staticDir + r.URL.Path[len(prefix):]
http.ServeFile(w, r, file)
started = true
return
}
}
requestPath := r.URL.Path
//Encontrar una ruta coincidente
for _, route := range p.routers {
//Comprobar si el patrón coincide con la ruta url
if !route.regex.MatchString(requestPath) {
continue
}
//Obtener subcoincidencias (params)
matches := route.regex.FindStringSubmatch(requestPath)
//Vuelve a comprobar que la ruta coincide con el patrón de URL.
if len(matches[0]) != len(requestPath) {
continue
}
params := make(map[string]string)
if len(route.params) > 0 {
//Añadir parámetros de URL al mapa param consulta
values := r.URL.Query()
for i, match := range matches[1:] {
values.Add(route.params[i], match)
params[route.params[i]] = match
}
//Volver a montar params consulta y agregar a RawQuery
r.URL.RawQuery = url.Values(values).Encode() + "&" + r.URL.RawQuery
//r.URL.RawQuery = url.Values(values).Encode()
}
// Invocar el manejador de peticiones
vc := reflect.New(route.controllerType)
init := vc.MethodByName("Init")
in := make([]reflect.Value, 2)
ct := &Context{ResponseWriter: w, Request: r, Params: params}
in[0] = reflect.ValueOf(ct)
in[1] = reflect.ValueOf(route.controllerType.Name())
init.Call(in)
in = make([]reflect.Value, 0)
method := vc.MethodByName("Prepare")
method.Call(in)
if r.Method == "GET" {
method = vc.MethodByName("Get")
method.Call(in)
} else if r.Method == "POST" {
method = vc.MethodByName("Post")
method.Call(in)
} else if r.Method == "HEAD" {
method = vc.MethodByName("Head")
method.Call(in)
} else if r.Method == "DELETE" {
method = vc.MethodByName("Delete")
method.Call(in)
} else if r.Method == "PUT" {
method = vc.MethodByName("Put")
method.Call(in)
} else if r.Method == "PATCH" {
method = vc.MethodByName("Patch")
method.Call(in)
} else if r.Method == "OPTIONS" {
method = vc.MethodByName("Options")
method.Call(in)
}
if AutoRender {
method = vc.MethodByName("Render")
method.Call(in)
}
method = vc.MethodByName("Finish")
method.Call(in)
started = true
break
}
//Si no hay coincidencias con el URL, una excepción que no se encuentra
if started == false {
http.NotFound(w, r)
}
}
Después de que el diseño se basa en el encaminamiento puede resolver el punto de restricción de tres mencionados anteriormente, usando un método de la siguiente manera:
El uso básico de una ruta registrada: beego.BeeApp.RegisterController("/", &controllers.MainController{})
Parameter registration:
beego.BeeApp.RegisterController("/:param", &controllers.UserController{})
Are then matched:
beego.BeeApp.RegisterController("/users/:uid([0-9]+)", &controllers.UserController{})
- Directory
- Previous section: Project program
- Next section: Design controllers