introduction
This article is the second article in the series [In-depth understanding of Go Standard Library]
Article 1:Starting of http server
Article 2: The use of ServeMux and pattern matching👈
According to the description in the Golang documentation,ServeMux
is an HTTP request multiplexer (HTTP Request multiplexer
). It matches the request URL and registered pattern according to certain rules and executes the most matching pattern.Handler
If you don't know what isHandler
, strongly recommend that you read it first:Article 1: Starting of http server
Basic use
Implemented
Handler
interface
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
Provide two functions to register different Path processing functions
What is received is
Handler
Interface implementation
type PathBar struct { } func (m PathBar) ServeHTTP(w , r *) { ([]byte("Receive path bar")) return } func main() { mx := () ("/bar/", PathBar{}) ("/foo", func(w , r *) { ([]byte("Receive path foo")) }) (":8009", mx) }
🌲 Implementing the interface through type conversion
It is worth mentioningThe implementation of the bottom layer is still called
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { if handler == nil { panic("http: nil handler") } (pattern, HandlerFunc(handler)) }
HandlerFunc(handler)
This is not a function call, but a type conversion
type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(w, r). func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
Byhandler func(ResponseWriter, *Request)
Convert to typeHandlerFunc
, and typeHandlerFunc
ImplementedHandler
interface
🌲 Global default value
When not setWhen attributes,
A global variable will be used
DefaultServeMux *ServeMux
Come asValue of
The following code is no different from the above
func main() { ("/bar/", PathBar{}) ("/foo", func(w , r *) { ([]byte("Receive path foo")) }) (":8009", nil) }
Pattern Matching
Preprocessing
The preprocessed isRequested url, for the convenience of matching, no processing will be done during registration
Remove the port number in the host
For URLs include
..
or.
ServeMux will sort out the path for requests and match them to the appropriate routing mode.For duplicates included in the URL
/
ServeMux will redirect the request
func main() { mx := () ("/abc/def", func(writer , request *) { (writer, , ) }) (":8009", mx) }
🌲 The preprocessed isRequested url
Patterns will not be processed, and the requested urls are processed into standard format
So if you register the following pattern, you will not be hit anyway
func main() { mx := () ("/abc//def", func(writer , request *) { (writer, , ) }) }
Whether it is/abc/def
still/abc//def
Can't be hit
$ curl 127.0.0.1:8009/abc/def 404 page not found $ curl 127.0.0.1:8009/abc//def <a href="/abc/def" rel="external nofollow" rel="external nofollow" >Moved Permanently</a>.
🌲 Bring..
or.
Request and duplication/
The request is handled differently
Include..
or.
After sorting out, match it to the appropriate routing mode.It will not be redirected
$ curl 127.0.0.1:8009/ccc/../abc/./def 127.0.0.1:8009 /abc/def
With duplicate/
, will redirect
$ curl -v 127.0.0.1:8009/abc//def * Trying 127.0.0.1:8009... * Connected to 127.0.0.1 (127.0.0.1) port 8009 (#0) > GET /abc//def HTTP/1.1 > Host: 127.0.0.1:8009 > User-Agent: curl/7.79.1 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 301 Moved Permanently < Content-Type: text/html; charset=utf-8 < Location: /abc/def < Date: Thu, 10 Nov 2022 16:05:13 GMT < Content-Length: 43 < <a href="/abc/def" rel="external nofollow" rel="external nofollow" >Moved Permanently</a>. * Connection #0 to host 127.0.0.1 left intact
Path Match
There are two ways to register a routing mode in ServeMux.Fixed root path
For example "/", withSubtree starting with root path
, for example "/images/"
🌲 Fixed paths (fixed, rooted paths)
Fixed root path
It is to specify a fixed URL to match the request exactly
🌲 The rooted subtrees
Subtree starting with root path
It conforms to the principle of longest path matching. For example, we have registered two subpaths./image/gif/
and/image/
, the URL is/image/gif/
The request will first match the first routing pattern, and other paths will match/image/
⚠️ Note:
1. Any/
The ending paths are all regarded as subtrees starting with the root path, so/
Also regarded as a subtree starting with a root path, it not only matches/
, and it will also match all requests that are not matched by other routing patterns.
func main() { mx := () ("/", func(writer , request *) { (writer, ()) }) (":8009", mx) }
$ curl 127.0.0.1:8009/abc /abc
2. If only one subtree path is registered (/
End) and the request URL does not/
At the end, ServeMux will return a redirect. If you add another one, no/
If the ending pattern will match exactly, there will be no such behavior.
For example, we only registered subpaths/abc/
The server will automatically/abc
Request redirection as/abc/
。
func main() { mx := () ("/abc/", func(writer , request *) { (writer, ()) }) (":8009", mx) }
$ curl -v 127.0.0.1:8009/abc * Trying 127.0.0.1:8009... * Connected to 127.0.0.1 (127.0.0.1) port 8009 (#0) > GET /abc HTTP/1.1 > Host: 127.0.0.1:8009 > User-Agent: curl/7.79.1 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 301 Moved Permanently < Content-Type: text/html; charset=utf-8 < Location: /abc/ < Date: Thu, 10 Nov 2022 15:30:13 GMT < Content-Length: 40 < <a href="/abc/" rel="external nofollow" >Moved Permanently</a>. * Connection #0 to host 127.0.0.1 left intact
If we don't want the server to redirect automatically, we just need to add another one/abc
Just the mode
func main() { mx := () ("/abc/", func(writer , request *) { (writer, ()) }) ("/abc", func(writer , request *) { (writer, ()) }) (":8009", mx) }
$ curl 127.0.0.1:8009/abc /abc
Domain name matching (Host-specific patterns)
ServeMux also supports exact matching based on the host name. When matching, the host will be strictly matched, and the path matching also follows the above principles.
⚠️ Note:
The priority of domain names will be higher, so you can register a path with domain names and a path without domain names.
func main() { mx := () ("/abc/", func(writer , request *) { (writer, , ()) }) ("/abc/", func(writer , request *) { (writer, , ()) }) (":8009", mx) }
Will match the first handler, and other domain names will match the second one
$ curl -H 'HOST:' 127.0.0.1:8009/abc/ /abc/ $ curl -H 'HOST:' 127.0.0.1:8009/abc /abc
Method and path parameter matching (method, path specific patterns)
The latest features are still being discussed, rough patterns will look like the following
/golang/go/discussions/60227
/item/ POST /item/{user} /item/{user} /item/{user}/{id} /item/{$} POST /item/{user}
The above is the detailed content of the in-depth exploration of the use and pattern matching of Go standard library - ServeMux. For more information about Go ServeMux pattern matching, please follow my other related articles!