Home>Article>Backend Development> How to quickly implement the Go Http Server framework? Done in one article

How to quickly implement the Go Http Server framework? Done in one article

藏色散人
藏色散人 forward
2022-12-13 16:55:45 4792browse

This article will introduce you to the relevant knowledge about Golang and talk about how to quickly implement the Go Http Server framework. I hope it will be helpful to everyone.

If you want to use http server in Go, the easiest way is to use http/net

err := http.ListenAndServe(":8080", nil)if err != nil { panic(err.Error())}http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("Hello"))})

define handle func [Related recommendations:Go video tutorial]

type HandlerFunc func(ResponseWriter, *Request)

The http server implementation of the standard library is very simple. Open a port and register a handler## that implementsHandlerFunc

#At the same time, the standard library also provides a method to completely take over the request

func main() { err := http.ListenAndServe(":8080", &Engine{}) if err != nil { panic(err.Error()) }}type Engine struct {}func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/hello" { w.Write([]byte("Hello")) }}
Define ServerHTTP

type Handler interface { ServeHTTP(ResponseWriter, *Request)}
If we need to write an HTTP Server framework, then we need to implement this method, and at the same time net The input and output streams of /http are not very convenient. We also need packaging, plus a simple Route, and do not write Path in ServeHTTP.

Here is a brief summary

  • An Engine that implements ServeHTTP

  • A Context that wraps the original input and output stream of HTTP

  • A Route that implements route matching

Route For the sake of simplicity, Map is used for complete matching

import ( "net/http")type Engine struct { addr string route map[string]handFunc}type Context struct { w http.ResponseWriter r *http.Request handle handFunc}type handFunc func(ctx *Context) errorfunc NewServer(addr string) *Engine { return &Engine{ addr: addr, route: make(map[string]handFunc), }}func (e *Engine) Run() { err := http.ListenAndServe(e.addr, e) if err != nil { panic(err) }}func (e *Engine) Get(path string, handle handFunc) { e.route[path] = handle}func (e *Engine) handle(writer http.ResponseWriter, request *http.Request, handle handFunc) { ctx := &Context{ w: writer, r: request, handle: handle, } ctx.Next()}func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { handleF := e.route[req.URL.Path] e.handle(w, req, handleF)}func (c *Context) Next() error { return c.handle(c)}func (c *Context) Write(s string) error { _, err := c.w.Write([]byte(s)) return err}
We write a Test Verify our Http Server

func TestHttp(t *testing.T) { app := NewServer(":8080") app.Get("/hello", func(ctx *Context) error { return ctx.Write("Hello") }) app.Run()}
The Handle we package here uses the Return error mode. Compared with the standard library, which only writes but does not return, it avoids errors caused by forgetting to return after not writing, which is usually difficult. Discover.

An Http Server also needs a middleware function. The idea here is to store an array of handleFunc in the Engine, which supports external registration. When a request comes in, a new Ctx is created and the global HandleFunc in the Engine is Copy it to Ctx, and then use c.Next() to implement matryoshka-style calling.

package httpimport ( "net/http")type Engine struct { addr string route map[string]handFunc middlewares []handFunc}type Context struct { w http.ResponseWriter r *http.Request index int handlers []handFunc}type handFunc func(ctx *Context) errorfunc NewServer(addr string) *Engine { return &Engine{ addr: addr, route: make(map[string]handFunc), middlewares: make([]handFunc, 0), }}func (e *Engine) Run() { err := http.ListenAndServe(e.addr, e) if err != nil { panic(err) }}func (e *Engine) Use(middleware handFunc) { e.middlewares = append(e.middlewares, middleware)}func (e *Engine) Get(path string, handle handFunc) { e.route[path] = handle}func (e *Engine) handle(writer http.ResponseWriter, request *http.Request, handle handFunc) { handlers := make([]handFunc, 0, len(e.middlewares)+1) handlers = append(handlers, e.middlewares...) handlers = append(handlers, handle) ctx := &Context{ w: writer, r: request, index: -1, handlers: handlers, } ctx.Next()}func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { handleF := e.route[req.URL.Path] e.handle(w, req, handleF)}func (c *Context) Next() error { c.index++ if c.index < len(c.handlers) { return c.handlers[c.index](c) } return nil}func (c *Context) Write(s string) error { _, err := c.w.Write([]byte(s)) return err}
The implementation method is very simple. Here we verify whether it can support pre- and post-middleware.

func TestHttp(t *testing.T) { app := NewServer(":8080") app.Get("/hello", func(ctx *Context) error { fmt.Println("Hello") return ctx.Write("Hello") }) app.Use(func(ctx *Context) error { fmt.Println("A1") return ctx.Next() }) app.Use(func(ctx *Context) error { err := ctx.Next() fmt.Println("B1") return err }) app.Run()}
Output:

=== RUN TestHttp A1 Hello B1
It only takes 100 lines of code in total, so we will A simple Http Server has been implemented. You can see the source code of Gin for subsequent details. The main focus is on Route and the implementation of the prefix tree.

The above is the detailed content of How to quickly implement the Go Http Server framework? Done in one article. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:learnku.com. If there is any infringement, please contact admin@php.cn delete