HandleFunc
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
// pattern 是 URI 的规则,例如 /
// handler 是供调用的函数
ListenAndServe
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
// addr 地址
// handler 通常为 nil,此种情况下会使用 DefaultServeMux
http.ServeMux
- Go 标准库 net/http 包里自带的 http.ServeMux
- 把收到的请求与一组预先定义的 URL 路径列表做对比,然后在匹配到路径的时候调用关联的处理器(Handler)
- 无法直接从路由上区分 POST 或者 GET 等 HTTP 请求方法,只能手动判断
- 不支持路由命名
- 不支持 URI 路径参数
- 徒增了代码的维护成本
package main
import (
"fmt"
"net/http"
"strings"
)
func main() {
router := http.NewServeMux()
router.HandleFunc("/", defaultHandler)
router.HandleFunc("/about", aboutHandler)
// 文章详情
router.HandleFunc("/article/", func(w http.ResponseWriter, r *http.Request) {
// 不支持 URI 路径参数,只能手动切割
id := strings.SplitN(r.URL.Path, "/", 3)[2]
fmt.Fprint(w, "文章id"+id)
})
// 列表 or 创建
// 无法直接从路由上区分 POST 或者 GET 等 HTTP 请求方法,只能手动判断
// 徒增了代码的维护成本
router.HandleFunc("/articles", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
fmt.Fprint(w, "访问文章列表")
case "POST":
fmt.Fprint(w, "创建新的文章")
}
})
// 用以监听本地 3000 端口以提供服务
http.ListenAndServe(":3000", router)
}
func defaultHandler(w http.ResponseWriter, r *http.Request) {
// 设置header头
if r.URL.Path == "/" {
fmt.Fprint(w, "<h1>Hello, 欢迎来到 goblog!</h1>")
} else {
w.WriteHeader(http.StatusNotFound)
fmt.Fprint(w, "<h1>请求页面未找到 :(</h1>"+
"<p>如有疑惑,请联系我们。</p>")
}
}
func aboutHandler(w http.ResponseWriter, r *http.Request) {
// 设置header头
w.Header().Set("Content-Type ", "text/html;charset=utf8")
fmt.Fprint(w, "<h1>this is go about</h1>")
}
HttpRouter
- 目前来讲速度最快的路由器,且被知名框架 Gin 所采用
- 路由功能相对简单,没有路由命名功能
- 适合在要求高性能,且路由功能要求相对简单的项目中使用
gorilla/mux
- 性能上虽然有所不及 HttpRouter,但是功能强大,全栈开发比较实用
- 实现了 net/http 包的 http.Handler 接口,故兼容 http.ServeMux
- 在 Gorilla Mux 中,如未指定请求方法,默认会匹配所有方法
安装
$ go get -u github.com/gorilla/mux
和 net/http 包区别
gorilla/mux 的路由解析采用的是 精准匹配 规则,而 net/http 包使用的是 长度优先匹配 规则。
router.HandleFunc("/", defaultHandler)
router.HandleFunc("/about", aboutHandler)
net/http:除了/
其他都进入/about
gorilla/mux:只能匹配/
和/about
,其他都是404
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/", homeHandler).Methods("GET").Name("home")
router.HandleFunc("/about", aboutHandler).Methods("GET").Name("about")
// 文章模块
// :区分正则,正则可省略
// Methods 指定请求方法,不指定则全匹配
// Name 指定路由命名
router.HandleFunc("/article/{id:[0-9]+}", articleShowHandler).Methods("GET").Name("article.show")
router.HandleFunc("/article", articleIndexHandler).Methods("GET").Name("article.index")
router.HandleFunc("/article", articleStoreHandler).Methods("POST").Name("article.store")
// 404
router.NotFoundHandler = http.HandlerFunc(notFoundHandler)
// 通过命名路由获取URL
homeURL, _ := router.Get("home").URL()
articleURL, _ := router.Get("article.show").URL("id", "23")
fmt.Println(homeURL, articleURL)
// 用以监听本地 3000 端口以提供服务
http.ListenAndServe(":3000", router)
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf8")
fmt.Fprint(w, "<h1>this is home</h1>")
}
func aboutHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf8")
fmt.Fprint(w, "<h1>this is about</h1>")
}
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf8")
fmt.Fprint(w, "<h1>请求页面未找到</h1>")
}
func articleShowHandler(w http.ResponseWriter, r *http.Request) {
// 会将 URL 路径参数解析为键值对应的 Map
vars := mux.Vars(r)
id := vars["id"]
fmt.Fprint(w, "文章详情:"+id)
}
func articleIndexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "文章列表")
}
func articleStoreHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "文章新增")
}
理解
- 并不是标准库里的就是最好了,不能被固有思想限制,很多第三方的库也很优秀,格局打开
题外话:新手入门,多有不解,理解有偏差请不吝指教