What is Context?
Context refers to the context of the standard library Context is an interface object, which is often used for asynchronous IO control and the transfer of context process variables. In GoFrame, context is mainly used to share data between processes.
What's the use of Context?
GoFrame is a network application development framework. There are a lot of IO operations in network applications. Using Context can reduce IO operations and improve operation efficiency.
For example, when users log in, they usually need to connect to the database to compare the user name and password. In addition, many modules in Web applications need to judge the account information and confirm the permission level before use, that is, each time the user clicks, the permission must be checked before subsequent operations can be carried out. Using Context, the user permission information can be stored in memory for use by all Web applications. In this way, the verification of permission by Web applications does not involve IO, which can greatly improve the operation efficiency.
Another example is the column and article list of the blog website, the menu of the hotel and the product list of the factory. These information should be obtained by many modules in the Web application. At this time, you can also use Context to cache and transfer these information.
In short, in Web applications, a large number of public data that are not changed frequently and read frequently can be cached into memory using Context to improve operation efficiency. However, when there are a large number of system users, such as tens of thousands or hundreds of thousands of online users, the login information is usually no longer cached in the Context, but cached by Redis.
How to use Context?
In Goframe, data description, data common methods and business logic should be distinguished and written in sequence.
Let's learn more about the use steps of Context through a practical case. First, set up the running environment, and then enter the ~ / go/src directory through the command line to execute the following commands:
gf init contextdemo
Next, open the contextdemo directory with Golan and follow it step by step.
Data definition
That is, the description of the data structure stored in the Context. File storage path app / API / model / Context go.
package model const ( // The ContextKey context variable stores the key name ContextKey = "ContextKey" ) // Context request context structure type Context struct { LoginName string // Login user name Authority string // User rights List []string // inventory }
Method definition
That is, initialization, reading, modification and other public interfaces / methods of data in Context. The file is stored in APP / API / service / Context go.
package service import ( "context" "contextdemo/app/model" "errors" "github.com/gogf/gf/net/ghttp" "io/ioutil" "strings" ) // Context context management service var Context = contextService{} type contextService struct{} // Init initializes the context object pointer into the context object so that it can be modified in subsequent request processes. func (s *contextService) Init(r *ghttp.Request, customCtx *model.Context) { r.SetCtxVar(model.ContextKey, customCtx) } // Get gets the context variable. If it is not set, it returns nil func (s *contextService) Get(ctx context.Context) *model.Context { value := ctx.Value(model.ContextKey) if value == nil { return nil } if localCtx, ok := value.(*model.Context); ok { return localCtx } return nil } // SetUser sets the context information into the context request. Note that it is a complete overwrite func (s *contextService) SetUser(ctx context.Context, name string) error { save := s.Get(ctx) if save == nil { return errors.New("context Information acquisition failed") } users := readUser() if _, ok := users[name]; ok { save.LoginName = name save.Authority = users[name] } else { return errors.New("user does not exist") } save.List = readProduct() return nil } // Simulate reading user information. Please modify the file path according to the running environment. func readUser() map[string]string { f, err := ioutil.ReadFile("/home/windf/go/src/contextdemo/app/model/users.txt") if err != nil { return nil } userList := strings.Split(string(f), "\n") list := make(map[string]string) for _, i := range userList { line := strings.Fields(i) list[line[0]] = line[1] } return list } // Simulate reading product information. Please modify the file path according to the running environment. func readProduct() []string { f, err := ioutil.ReadFile("/home/windf/go/src/contextdemo/app/model/list.txt") if err != nil { return nil } list := strings.Split(string(f), "\n") return list } // Simulate login var loginName = "Zhang San" func login() string { return loginName } // ListTable gets the product list in the context func (s *contextService) ListTable(ctx context.Context) []string { if v := Context.Get(ctx); v != nil { return v.List } return nil } // AuthZero changing user permissions in context func (s *contextService) AuthZero(ctx context.Context) { if v := Context.Get(ctx); v != nil { v.Authority = "0" } }
remarks:
There are 2 text files in the above code. Please modify the path according to the running environment. In addition, the contents of the document are as follows:,
list.txt
mouse keyboard monitor loudspeaker box
users.txt
Zhang San 1 Li Si 2 Wang Wu3
Middleware definition
Context middleware is to complete the initialization and transmission of data in context. The file is stored in APP / API / service / middleware go.
package service import ( "contextdemo/app/model" "fmt" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" ) // Middleware management service var Middleware = middlewareService{} type middlewareService struct{} // Ctx custom context object func (s *middlewareService) Ctx(r *ghttp.Request) { // Initialization must be performed at the beginning name := login() users:=readUser() if _, ok := users[name]; ok { customCtx := model.Context{ LoginName: name, Authority: users[name], List: readProduct(), } Context.Init(r, &customCtx) // Pass the key value pair in the context object to the template r.Assigns(g.Map{ "user":customCtx.LoginName, "auth":customCtx.Authority, "list":customCtx.List, }) }else{ fmt.Println("User does not exist, please login again") // This is to simplify the demonstration. Normally, it should be handled in the login verification function } // Execute subsequent Middleware r.Middleware.Next() }
Middleware registration
The middleware must be registered in the corresponding router to take effect. The file is stored in router / router go.
package router import ( "context/app/api" "context/app/service" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" ) func init() { s := g.Server() s.Group("/", func(group *ghttp.RouterGroup) { group.Middleware(service.Middleware.Ctx) // Register context related Middleware group.ALL("/hello", api.Hello) }) }
Use Context in application
Use Context information in template file
Note that r.assignments should be registered in the middleware and the variables in the middleware should be registered in the variable list accessible to the template file.
Write the template file hello html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> User:{{.user}}<br> jurisdiction:{{.auth}}<br> Products:{{.list}} </body> </html>
Read Context information in the application
There are two reading methods. See the code:
package api import ( "contextdemo/app/service" "fmt" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" ) var Hello = helloApi{} type helloApi struct {} // Index is a demonstration route handler for output "Hello World!". func (*helloApi) Index(r *ghttp.Request) { list1 := r.GetCtxVar("ContextKey").Map()["List"] // This method can obtain the data in the Context list2 :=service.Context.ListTable(r.Context()) // You can also use custom methods to extract the required data fmt.Println(list1) fmt.Println(list2) service.Context.AuthZero(r.Context()) // Call the method to change the user permissions in the context auth := r.GetCtxVar("ContextKey").Map()["Authority"] fmt.Println(auth) // Note that although the auth value is modified at this time, it will not take effect if r.assignments is not executed in the template r.Assigns(g.Map{ "user":r.GetCtxVar("ContextKey").Map()["LoginName"], "auth":r.GetCtxVar("ContextKey").Map()["Authority"], "list":r.GetCtxVar("ContextKey").Map()["List"], }) // After the r.assignments method is executed, it will take effect in the template file err := r.Response.WriteTpl("hello.html") if err != nil { r.Response.Writeln(err) return } }
Modify Context information in application
Generally, the modification methods involving Context information are written in service / Context In go, the Context information is not directly modified in the application. It is recommended to modify the information by calling the method corresponding to the service.
supplement
After the above code is edited, if the following error is encountered during compilation and execution:
go: github.com/gogf/gf@v1.16.4: missing go.sum entry; to add it: go mod download github.com/gogf/gf
Please refer to the prompt to execute the corresponding instruction on the command line. For example, the prompt above should execute go mod download GitHub com/gogf/gf.
The same is true if you encounter an error in the figure below:
Please refer to the error message and execute the corresponding statements on the command line in turn:
go get github.com/gogf/gf/encoding/gyaml@v1.16.4 go get github.com/gogf/gf/encoding/gcharset@v1.16.4 go get github.com/gogf/gf/net/ghttp/internal/client@v1.16.4 go get github.com/gogf/gf/net/ghttp@v1.16.4 go get github.com/gogf/gf/net/gtrace@v1.16.4 go get github.com/gogf/gf/encoding/ghtml@v1.16.4 go get github.com/gogf/gf/database/gdb@v1.16.4 go get github.com/gogf/gf/os/gfsnotify@v1.16.4
Finishing
visit http://127.0.0.1:8199/hello , you can see the following information, indicating that the context data has been successfully obtained: