Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the use of Handler in Go language

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)05/31 Report--

This article mainly introduces "what is the use of Handler in Go language". In daily operation, I believe that many people have doubts about the use of Handler in Go language. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the doubts about "what is the use of Handler in Go language?" Next, please follow the editor to study!

Multiplexer routes the request to the specified Handler based on the URL. Handler is used to process requests and give responses. More strictly, it is used to read the request body and write the corresponding response field (respones header) of the request to ResponseWriter, and then return.

What is Handler?

What is Handler. It is an interface defined in net/http/server.go:

Type Handler interface {ServeHTTP (ResponseWriter, * Request)}

In other words, it is Handler that implements the ServerHTTP method. Note the parameters of the ServerHTTP method: the http.ResponesWriter interface and the Request pointer.

In the comments of Handler, several main points are given:

Handler is used to respond to a HTTP request

The interface method ServerHTTP should be used to write the response header and the data that needs to be responded to to the ResponseWriter, and then return. The return means that the request has been processed, the ResponseWriter can no longer be used, the data can no longer be read from Request.Body, and the completed ServerHTTP method cannot be called concurrently.

Handler should read Request.Body before writing ResponseWriter. As long as you start writing data to ResponseWriter, you can no longer read data from Request.Body

Handler can only be used to read the body of request, and the acquired Request cannot be modified (because its parameter Request is of pointer type)

ResponseWriter interface description

Let's take a look at the definition of ResponseWriter interface:

/ / A ResponseWriter interface is used by an HTTP handler to// construct an HTTP response.//// A ResponseWriter may not be used after the Handler.ServeHTTP method// has returned.type ResponseWriter interface {Header () Header Write ([] byte) (int, error) WriteHeader (statusCode int)}

As stated in the comments, the purpose of the ResponseWriter interface is to construct HTTP response. And explicitly specify that ResponseWriter can no longer be used after the Handler.ServerHTTP method returns.

There are three methods for this interface:

The Header () method is used to construct the response Header, which returns a Header object that will later be responded to by WriterHeader (). The Header type is a structure of type map with a field name of key and a field value of value:

Type Header map [string] [] string

The Write () method is used to write response data to a network connection.

The WriteHeader () method sends the given response status code along with the response Header.

Obviously, the role of ResponseWriter is to construct the response header and send the response header and response data to the client over a network link.

Take a look at ListenAndServe ()

The function ListenAndServe () is called when the web service that comes with go http is started. This function is defined as follows:

Func ListenAndServe (addr string, handler Handler) error

The function has two parameters. The first parameter is the built-in web listening address and port, and the second parameter is Handler, which is used to handle each incoming http request. But generally, the second parameter is set to nil, which means that the default Multiplexer:DefaultServeMux is called. The only function of this default ServeMux is to route the request to the corresponding handler for processing according to the URL.

Var DefaultServeMux = & defaultServeMux

Here are two questions:

(1)。 Why is the second parameter recommended to be set to nil

(2)。 When set to nil, DefaultServeMux is the requesting router. Why can it act as a handler?

Let's look at the second question first, which is simple, because the ServeMux type defines the ServeHTTP () method, which implements the Handler interface:

Type ServeMux struct {/ / Has unexported fields.} func NewServeMux () * ServeMuxfunc (mux * ServeMux) Handle (pattern string, handler Handler) func (mux * ServeMux) HandleFunc (pattern string, handler func (ResponseWriter, * Request) func (mux * ServeMux) Handler (r * Request) (h Handler, pattern string) func (mux * ServeMux) ServeHTTP (w ResponseWriter, r * Request)

As mentioned earlier, as long as the type of the ServerHTTP () method is implemented, it is a Handler. DefaultServeMux is the default ServeMux, so it is a Handler.

As for the first question, just look at an example.

Package mainimport ("fmt"net/http") / / MyHandler implements the Handler interface type MyHandler struct {} func (h * MyHandler) ServeHTTP (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "Hello World!\ n")} func main () {handler: = MyHandler {} server: = http.Server {Addr: "127.0.0.1 fmt.Fprintf 8080" Handler: & handler, / / take & handler as the second parameter} server.ListenAndServe ()}

In the above example, a handler is defined, and the ServeHTTP () method it implements has only one function, outputting Hello World!. And take this handler as the second parameter of ListenAndServe ().

Note that the above takes & handler as a parameter rather than handler, because the receiver of the ServerHTTP () method implemented in MyHandler here is of pointer type, so the instance object of MyHandler must also be of pointer type in order to implement the Handler interface.

When you start the web service and access it with a different URL, you will always get exactly the same response:

Obviously, when handler is the second parameter of ListenAndServe (), any request will be processed using this unique handler.

Therefore, it is recommended that the second parameter be set to nil (or the above Serve Struct does not specify the Handler field), which means that the default DefaultServeMux is called as handler, so that this special handler is called for each access request, and the purpose of this handler is to route the request to a different handler based on the url.

It is also important to note that the Handle () and HandleFunc () functions provided in the http package are actually DefaultServeMux.XXX wrappers, so calling http.Handle () and http.HandleFunc () directly is actually calling DefaultServeMux.Handle () and DefaultServeMux.HandleFunc ().

Func Handle (pattern string, handler Handler) {DefaultServeMux.Handle (pattern, handler)} func HandleFunc (pattern string, handler func (ResponseWriter, * Request)) {DefaultServeMux.HandleFunc (pattern, handler)} Handler example after using DefaultServeMux

The following is an example of using DefaultServeMux.

Two handler are created, one handler for the corresponding / hello, the handler for the output Hello, and the other handler for the corresponding world, and the handler for the output World:

Package mainimport ("fmt"net/http") type HelloHandler struct {} type WorldHandler struct {} func (h * HelloHandler) ServeHTTP (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "Hello\ n")} func (h * WorldHandler) ServeHTTP (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w "World\ n")} func main () {helloHandler: = HelloHandler {} worldHandler: = WorldHandler {} server: = http.Server {Addr: "127.0.0.1 helloHandler 8080",} http.Handle ("/ hello", & helloHandler) http.Handle ("/ world", & worldHandler) server.ListenAndServe ()}

Here are the results of the interview:

What is HandleFunc?

In addition to using Handle to handle http requests, you can also use HandleFunc () processing.

Let's first look at an example of using HandleFunc () to process a request, and the effect of the example is the same as the previous one.

Package mainimport ("fmt"net/http") func hello (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "Hello\ n")} func world (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "World\ n")} func main () {server: = http.Server {Addr: "127.0.0.1 fmt.Fprintf 8080" } http.HandleFunc ("/ hello", hello) http.HandleFunc ("/ world", world) server.ListenAndServe ()}

Here are the results of the interview:

Go has a function HandleFunc (), which means that the function with the second argument is used as a handler to handle the matching url path request.

Func HandleFunc (pattern string, handler func (ResponseWriter, * Request))

It's not hard to see that HandleFunc () allows you to directly use a function as a handler without having to customize a type that implements the Handler interface. As in the example above, we don't define the Handler type, nor do we implement the ServeHTTP () method. Instead, we define the function directly and use it as a handler.

In other words, HandleFunc () makes it easier for us to register handler for certain url paths. However, it is easy to use HandleFunc () after all, and sometimes you have to use Handle (), for example, we are sure to define a type.

The relationship between Handle (), HandleFunc () and Handler, HandlerFunc

To tell you the truth, it felt quite messy at first.

Handle () and HandleFunc () are functions that bind handler to url. Handler and HandlerFunc types, which are used to process requests.

The definitions of Handle (), HandleFunc (), Handler and HandlerFunc are already clear:

Func Handle (pattern string, handler Handler) {} func HandleFunc (pattern string, handler func (ResponseWriter, * Request)) {} type Handler interface {ServeHTTP (ResponseWriter, * Request)} type HandlerFunc func (ResponseWriter, * Request) func (f HandlerFunc) ServeHTTP (w ResponseWriter, r * Request)

Both Handle () and HandleFunc () bind a corresponding handler for a url path pattern, except that HandleFunc () directly uses the function as the handler, while Handle () uses an instance of type Handler as the handler.

The instances of the Handler interface implement the ServeHTTP () method, which is used to process the request and respond to the client.

The HandlerFunc type is not an interface, but it has a method ServeHTTP (), which means that HandlerFunc is actually a Handler.

Because HandlerFunc is a type, as long as a function's signature is func (ResponseWriter, * Request), it is an instance of the HandlerFunc type. On the other hand, instances of this type (which may be parameters or return value types) can be assigned to each other with a function signed func (ResponseWriter, * Request). This process may be implicit, but related uses do occur frequently.

For example:

/ / handlerfunc myhf of a function type (ResponseWriter, * Request) {} / / take the HandlerFunc type as the parameter type func a (hf HandlerFunc) {} / / so you can take myhf as the parameter a (myhf) of a ()

In fact, you can use HandlerFunc () for the transformation. For example, there is a function world (), whose arguments are reasonable, using HandlerFunc (world) to indicate that it is converted to a Handler. This conversion and adaptation will be often used later.

For example:

/ / two functions func hello (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "Hello\ n")} func world (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "World\ n")} func main () {server: = http.Server {Addr: "127.0.0.1 Hello 8080" } / / the first one uses HandleFunc () to register the hello () function handler / / the second one uses Handle () to register the converted handler http.HandleFunc ("/ hello", hello) http.Handle ("/ world", http.HandlerFunc (world)) server.ListenAndServe ()}

In the above example, the second argument to the Handle () function requires the Handler type, and using http.HandlerFunc (world) converts the function world () to an instance of the Handler type.

Chain handler

Handler is used to process http requests, which can be simple or complex. In complex cases, it may not be possible to use a single handler to get the job done. After all, handler is just a function. Although we can call other functions directly in this function.

Very often, it is possible that other handler or even multiple layers of nesting are needed in handler, which is called chained handler.

Because you need to specify the parameter type when registering Handle () or HandleFunc (), you should also pay attention to the parameter type and return type of handler when handler is nested. See the following example to see how parameter types and return types are required.

Nesting example of HandleFunc ()

The code is as follows:

Package mainimport ("fmt"net/http") func hello (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "Hello World!\ n")} func log (hf http.HandlerFunc) http.HandlerFunc {count: = 0 return func (w http.ResponseWriter, r * http.Request) {count++ fmt.Printf ("Handler Function called% d times\ n") Count) hf (w, r)}} func main () {server: = http.Server {Addr: "127.0.0.1 server.ListenAndServe 8080",} http.HandleFunc ("/ hello", log (hello)) server.ListenAndServe ()}

Multiple visits to http://127.0.0.1:8080/hello will output "Hello World!" in the browser, but the following will be output multiple times on the terminal running the go program:

$go run test.goHandler Function called 1 timesHandler Function called 2 timesHandler Function called 3 timesHandler Function called 4 timesHandler Function called 5 times

In the above example, we mainly look at the following two pieces of code:

Func hello (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "Hello World!\ n")} func log (hf http.HandlerFunc) http.HandlerFunc {count: = 0 return func (w http.ResponseWriter, r * http.Request) {count++ fmt.Printf ("Handler Function called% d times\ n", count) hf (w, r)}}

Hello () is a normal HandlerFunc type function, and because its signature matches the HandlerFunc type, it is an instance of the HandlerFunc type. The log () function takes the HandlerFunc type as an argument, so in the previous sample code, the hello function is taken as a parameter to the log function:

Http.HandleFunc ("/ hello", log (hello))

The second parameter of HandleFunc () requires that it be of type HandlerFunc, so the return value of log () is of type HandlerFunc. In log (), an anonymous function is used as its return value, and the anonymous function here is a closure (because the variables hf and count of the outer function are referenced). This anonymous function ends up calling hf (wjournal r), which can be called because hf is an instance of the HandlerFunc type.

The above shows some details about parameters and return values when HandlerFunc is nested.

There is another detail to note in the above example: why the above count remembers the previous value and increments itself each time it is accessed, instead of resetting to 0.

The reason for this doubt may be that the handler exits after the request processing is completed for each visit. Although the closure remembers the free variable count of the outer function, it will also exit after the processing is completed, resulting in the auto-increment of reset to 0 for each access. But in fact, the handler is registered on a given path, and as long as the web service does not exit, the handler will not exit and will not re-register the handler for each visit. Therefore, the closure handler always refers to two free variables, hf and count.

HandlerFunc nested Handler

Change the above HandlerFunc nested HandlerFunc to Handler nested HandlerFunc.

Package mainimport ("fmt"net/http") type MyHandler struct {} func (wh * MyHandler) ServeHTTP (w http.ResponseWriter, r * http.Request) {fmt.Fprintf (w, "Hello World!\ n")} func log (h http.Handler) http.Handler {count: = 0f: = func (w http.ResponseWriter) R * http.Request) {count++ fmt.Printf ("Handler Function called% d times\ n", count) h.ServeHTTP (w, r)} return http.HandlerFunc (f)} func main () {myHandler: = MyHandler {} server: = http.Server {Addr: "127.0.0.1 times 8080" } http.Handle ("/ hello", log (& myHandler)) server.ListenAndServe ()}

The logic is also simple, which is nothing more than converting HandlerFunc to Handler.

Consider whether Handler can nest Handler, or Handler can nest HandlerFunc. Yes, but it's inconvenient, because the ServeHTTP () method limits the ability to call other Handler unless one of the defined Handler is a type nested within a Handler type.

At this point, the study of "what is the use of Handler in Go language" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report