Skip to content

Latest commit

 

History

History
276 lines (209 loc) · 10.3 KB

File metadata and controls

276 lines (209 loc) · 10.3 KB

13.2 Customized routers

HTTP routing

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).

La ruta predeterminada para lograr

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
	}
}

Beego routing framework to achieve

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

Almacenamiento de un enrutamiento

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)

}

Static routing

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

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)
	}
}

Primeros pasos

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{})

Links