golang implements the routing scheduling detail with less than 20 lines of code

  • 2020-06-15 09:16:28
  • OfStack

preface

This paper mainly introduces the implementation of golang routing scheduling related content, Shared for your reference and learning, the following words do not say much, let's have a look at the detailed introduction

The project address

github (local download)

This project depends on

Standard library implementation with no additional dependencies

Why is the routing scheduling layer needed

[

The golang http standard library can only precisely match the requested URI and then execute handler. Every web project now has at least one Controller layer, implemented as struct, distributed to different methods according to different request paths.

]

Routing scheduler definition

Since golang cannot create objects dynamically for the time being (for example java's Class.forName ("xxx").newInstance (),xxx is an arbitrary class name). So you need to register 1 controller relationship manually.

Define routes to hold the controller pointer Parse request URL query parameters, provisional a for action name,c for controller name, this article stole the lazy, did not do the processing of PATH_INFO, also did not automatically capitalized the first letter of actionName, this does not affect the core content of this article to convey, interested readers can realize by themselves. Find the corresponding controller according to controllerName in URL Use reflection to set * http.Request and http.ResponseWriter for the current request object to that Controller Use reflection and actionName versus controller

Since the inheritance of golang is not 1-like OOP, there is no such thing as a parent-child class. Only interface{} can be used for route registration.

Code implementation

app/app.go

This file is the core scheduling file

package app


import (
 "net/http"
 "reflect"
 "fmt"
)

type application struct {
 routes map[string]interface{}
}

func New() *application {
 return &application{
  routes: make(map[string]interface{}),
 }
}

func (p *application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 controllerName := r.URL.Query().Get("c")
 actionName := r.URL.Query().Get("a")
 if controllerName == "" || actionName == "" {
  http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  return
 }
 route, ok := p.routes[controllerName]
 if !ok {
  http.Error(w, "Controller Not Found", http.StatusNotFound)
  return
 }
 ele := reflect.ValueOf(route).Elem()
 ele.FieldByName("Request").Set(reflect.ValueOf(r))
 ele.FieldByName("Response").Set(reflect.ValueOf(w))
 ele.MethodByName(actionName).Call([]reflect.Value{})
}

func (p *application) printRoutes() {
 for route, controller := range p.routes {
  ele := reflect.ValueOf(controller).Type().String()
  fmt.Printf("%s %s\n", route, ele)
 }
}

func (p *application) Get(route string, controller interface{}) {
 p.routes[route] = controller
}

func (p *application) Run(addr string) error {
 p.printRoutes()
 fmt.Printf("listen on %s\n", addr)
 return http.ListenAndServe(addr, p)
}

app/controller.go

Controller "Base class"


package app

import "net/http"

type Controller struct {
 Response http.ResponseWriter
 Request *http.Request
}

controller/site.go

Concrete business logic classes


package controllers

import (
 "fmt"
 "app"
)

type SiteController struct {
 app.Controller
}

func (p SiteController) Index() {
 fmt.Fprint(p.Response, p.Request.RequestURI)
}

main.go

Entrance to the file


package main

import (
 _ "github.com/go-sql-driver/mysql"
 "app"
 "controllers"
)

func main() {
 application := app.New()
 application.Get("site", &controllers.SiteController{})
 application.Run(":8080")
}

Run the project

Start the process

Visit http: / / localhost: 8080 & # 63; c = site & a=Index will print /? c = site & a=Index

Write in the last

I hope this small project can inspire readers to develop their own Web framework as soon as possible!


Related articles: