httprouter

一句话描述

httprouter是一个轻量的、高效的http请求路由器,对http请求进行路由转发

入门示例

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "log"
  6. "github.com/julienschmidt/httprouter"
  7. )
  8. func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
  9. fmt.Fprint(w, "Welcome!\n")
  10. }
  11. func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
  12. fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
  13. }
  14. func main() {
  15. router := httprouter.New()
  16. router.GET("/", Index)
  17. router.GET("/hello/:name", Hello)
  18. log.Fatal(http.ListenAndServe(":8080", router))
  19. }
  1. curl http://127.0.0.1:8080
  2. Welcome!
  3. curl http://127.0.0.1:8080/hello/golang
  4. hello, golang!

命名参数

匹配一个路由段

语法:

:param_name

示例:

  1. router.GET("/src/:filename", func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
  2. fileName := params.ByName("filename")
  3. fmt.Fprintf(writer, "文件名是: %s\n", fileName)
  4. })
  1. curl http://127.0.0.1:8080/src/icon
  2. 文件名是: icon

匹配多个路由段

语法:

*param_name

示例:

  1. router.GET("/src/*filename", func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
  2. fileName := params.ByName("filename")
  3. fmt.Fprintf(writer, "文件路径是: %s\n", fileName)
  4. })
  1. curl http://127.0.0.1:8080/src/pic/icon.jpg
  2. 文件路径是: /pic/icon.jpg

路由解析

httprouter为了提高路由匹配的性能,路由解析采用的是prefix tree or Radix tree 方式对路由进行解析,该解析方式在进行路由匹配时,可以实现O(n) 的时间复杂度

示例:

路由 handle
/ *<1>
/search/ *<2>
/support/ *<3>
/blog/ *<4>
/blog/:post/ *<5>
/about-us/ *<6>
/about-us/team/ *<7>
/contact/ *<8>

解析后结构

  1. Priority Path Handle
  2. 9 \ *<1>
  3. 3 |-s nil
  4. 2 |-earch\ *<2>
  5. 1 |-upport\ *<3>
  6. 2 |-blog\ *<4>
  7. 1 |-:post nil
  8. 1 |-\ *<5>
  9. 2 |-about-us\ *<6>
  10. 1 |-team\ *<7>
  11. 1 |-contact\ *<8>

架构示意图

每日一库之84:httprouter - 图1

底层数据结构

路由

Router是所有配置及路由解析后节点树的载体

  1. type Router struct {
  2. // 节点树,key为method,value为节点树指针
  3. trees map[string]*node
  4. // 为true时,启动RedirectTrailingSlash策略:如果当前uri没有命中任何路由项,但是存在与当前uri只有一个尾部
  5. // 斜杠出路的路由项,例如请求uri为/foo/,路由项中并不能命中,但是存在/foo路由项,则会
  6. // 返回客户端重定向地址,如果请求方法是GET,则返回状态为301,其他请求方法返回307
  7. RedirectTrailingSlash bool
  8. // 为true时,启动RedirectFixedPath策略:如果当前uri没有命中任何路由项。
  9. // 首先:移除多余的路由元素,如../ 或 //
  10. // 其次:对修复后的uri进行忽略大小写的匹配,如果可以匹配到,则路由器将会重定向到匹配到的uri,
  11. // 如果是GET请求,则response 状态为301,否则为307
  12. // 例如 /FOO 和 /..//FOO 可以重定向到/foo
  13. RedirectFixedPath bool
  14. // 为true时,启动HandleMethodNotAllowed策略:如果当前请求对应的方法不支持该请求,
  15. // 则路由器将会检测其他方法是否支持该请求,如果MethodNotAllowed存在,则通过
  16. // MethodNotAllowed处理请求,否则返回405异常
  17. HandleMethodNotAllowed bool
  18. // 为true时,启动HandleOPTIONS策略:路由器支持自动回复,response头信息中含有支持请求的方法。
  19. // 如果有自定义handle处理该请求,则自定义handle处理
  20. HandleOPTIONS bool
  21. // 一个可选的http.Handler,在OPTIONS请求时可以被自动调用
  22. // HandleOPTIONS为true,而且当前的path没有针对的OPTIONS handle时,GlobalOPTIONS将会被调用
  23. // 在GlobalOPTIONS被调用前 header头Allowed参数将会被设置
  24. GlobalOPTIONS http.Handler
  25. // 缓存全局的被允许的请求方法
  26. globalAllowed string
  27. // 一个可选的http.Handler,用于在没有匹配的路由项时调用;如果该值没有设置,则使用http.NotFound
  28. NotFound http.Handler
  29. // 一个可选的http.Handler用于当一个请求没有对应的路由项而且HandleMethodNotAllowed为true时被调用。
  30. // 如果该值没有被设置,则返回一个405异常。
  31. // 调用Met hodNotAllowed之前,header头 Allow参数将会被设置
  32. MethodNotAllowed http.Handler
  33. // 该handle用于处理http handles处理过程中发生的panics
  34. // 它应该用来生成一个错误页面并返回http错误代码
  35. // 该handle可以用来避免你的服务因panics而导致崩溃
  36. PanicHandler func(http.ResponseWriter, *http.Request, interface{})
  37. }

节点

节点树的组成元素

  1. // 节点
  2. type node struct {
  3. path string // 节点路径
  4. wildChild bool // 是否存在通配符标识
  5. nType nodeType // 节点类型
  6. maxParams uint8 // 最大参数数量
  7. priority uint32 // 优先级
  8. indices string // 子节点path首字母索引,顺序与children一致
  9. children []*node // 子节点列表
  10. handle Handle // 处理程序
  11. }

节点类型

  1. type nodeType uint8
  2. // 支持4种类型
  3. const (
  4. static nodeType = iota // 静态路由
  5. root // 根节点
  6. param // 命名参数
  7. catchAll // catch-all命名参数
  8. )

request处理程序

自定义request处理程序都要实现该函数类型

  1. type Handle func(http.ResponseWriter, *http.Request, Params)

路由参数

  1. type Param struct {
  2. Key string
  3. Value string
  4. }

路由参数列表

  1. type Params []Param

源文件

path.go

到目前版本为止(v1.3.0),path文件只有一个方法CleanPath,CleanPath方法的作用是规范化HTTP request请求路由,以便最大可能找到想匹配的路由,在 RedirectFixedPath参数生效的前提下,重定向到匹配到的路由项

tree.go

该文件存储node相关方法及配置

  • addRoute:解析路由项到节点树
  • getValue:通过request path匹配路由项

router.go

httprouter整体功能都是在该文件中实现

  • ServeHTTP:实现http.Handler接口,接收net/http调用,对http request请求进行路由转发
  • Handle:路由解析底层实现,经过封装支持 GET、 POST、 PUT、 PATCH、 DELETE等method路由项解析

链接

Github:https://github.com/julienschmidt/httprouter

GoDoc:https://pkg.go.dev/github.com/julienschmidt/httprouter