mirror of
https://github.com/geektutu/7days-golang.git
synced 2024-04-21 12:32:11 +00:00
add day1 & day2 code
This commit is contained in:
+2
-1
@@ -1 +1,2 @@
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
tmp
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
## [目录](https://geektutu.com/post/gee.html)
|
||||
|
||||
- 第一天:前置知识(http.Handler接口)
|
||||
- 第二天:Tire树实现路由(Router)
|
||||
- 第三天:支持模板(HTML Template)
|
||||
- 第四天:JSON & RESTful API
|
||||
- [第一天:前置知识(http.Handler接口)](https://geektutu.com/post/gee-day1.html)
|
||||
- [第二天:Tire树实现路由(Router)](https://geektutu.com/post/gee-day2.html)
|
||||
- 第三天:设计Context
|
||||
- 第四天:支持模板(HTML Template)
|
||||
- 第五天:支持中间件(Middleware)
|
||||
- 第六天:简单鉴权(BASIC AUTH)
|
||||
- 第七天:异常错误处理(Panic)
|
||||
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
// $ curl http://localhost:9999/
|
||||
// URL.Path = "/"
|
||||
// $ curl http://localhost:9999/hello
|
||||
// Header["Accept"] = ["*/*"]
|
||||
// Header["User-Agent"] = ["curl/7.54.0"]
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", indexHandler)
|
||||
http.HandleFunc("/hello", helloHandler)
|
||||
log.Fatal(http.ListenAndServe(":9999", nil))
|
||||
}
|
||||
|
||||
// handler echoes r.URL.Path
|
||||
func indexHandler(w http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
|
||||
}
|
||||
|
||||
// handler echoes r.URL.Header
|
||||
func helloHandler(w http.ResponseWriter, req *http.Request) {
|
||||
for k, v := range req.Header {
|
||||
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
// $ curl http://localhost:9999/
|
||||
// URL.Path = "/"
|
||||
// $ curl http://localhost:9999/hello
|
||||
// Header["Accept"] = ["*/*"]
|
||||
// Header["User-Agent"] = ["curl/7.54.0"]
|
||||
// curl http://localhost:9999/world
|
||||
// 404 NOT FOUND: /world
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Engine is the uni handler for all requests
|
||||
type Engine struct{}
|
||||
|
||||
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
switch req.URL.Path {
|
||||
case "/":
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
|
||||
case "/hello":
|
||||
for k, v := range req.Header {
|
||||
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
engine := new(Engine)
|
||||
log.Fatal(http.ListenAndServe(":9999", engine))
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HandlerFunc defines the request handler used by gee
|
||||
type HandlerFunc func(http.ResponseWriter, *http.Request)
|
||||
|
||||
// Engine implement the interface of ServeHTTP
|
||||
type Engine struct {
|
||||
router map[string]HandlerFunc
|
||||
}
|
||||
|
||||
// New is the constructor of gee.Engine
|
||||
func New() *Engine {
|
||||
return &Engine{router: make(map[string]HandlerFunc)}
|
||||
}
|
||||
|
||||
// GET defines the method to add GET request
|
||||
func (engine *Engine) GET(pattern string, handler HandlerFunc) {
|
||||
engine.router[pattern] = handler
|
||||
}
|
||||
|
||||
// Run defines the method to start a http server
|
||||
func (engine *Engine) Run(addr string) (err error) {
|
||||
return http.ListenAndServe(addr, engine)
|
||||
}
|
||||
|
||||
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
if handler, ok := engine.router[req.URL.Path]; ok {
|
||||
handler(w, req)
|
||||
} else {
|
||||
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
// $ curl http://localhost:9999/
|
||||
// URL.Path = "/"
|
||||
// $ curl http://localhost:9999/hello
|
||||
// Header["Accept"] = ["*/*"]
|
||||
// Header["User-Agent"] = ["curl/7.54.0"]
|
||||
// curl http://localhost:9999/world
|
||||
// 404 NOT FOUND: /world
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"./gee"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.GET("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
|
||||
})
|
||||
|
||||
r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
|
||||
for k, v := range req.Header {
|
||||
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
|
||||
}
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Params map[string]string
|
||||
|
||||
func (ps *Params) Get(key string) string {
|
||||
if value, ok := (*ps)[key]; ok {
|
||||
return value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ps *Params) set(key string, value string) {
|
||||
(*ps)[key] = value
|
||||
}
|
||||
|
||||
// HandlerFunc defines the request handler used by gee
|
||||
type HandlerFunc func(http.ResponseWriter, *http.Request, *Params)
|
||||
|
||||
// Engine is defined to handle all requests
|
||||
type Engine struct {
|
||||
router *router
|
||||
}
|
||||
|
||||
// New is constructor of Engine
|
||||
func New() *Engine {
|
||||
return &Engine{
|
||||
router: &router{root: &node{}},
|
||||
}
|
||||
}
|
||||
|
||||
// GET defines the method to add GET request
|
||||
func (engine *Engine) GET(pattern string, handler HandlerFunc) {
|
||||
engine.router.addRoute(pattern, handler)
|
||||
}
|
||||
|
||||
// Run defines the method to start a http server
|
||||
func (engine *Engine) Run(addr string) (err error) {
|
||||
return http.ListenAndServe(addr, engine)
|
||||
}
|
||||
|
||||
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
if n, params := engine.router.getRoute(req.URL.Path); n != nil {
|
||||
n.handler(w, req, params)
|
||||
} else {
|
||||
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package gee
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type router struct {
|
||||
root *node
|
||||
}
|
||||
|
||||
func (r *router) addRoute(path string, handler HandlerFunc) {
|
||||
parts := filterNonEmpty(strings.Split(path, "/"))
|
||||
r.root.insert(path, parts, handler, 0)
|
||||
}
|
||||
|
||||
func (r *router) getRoute(path string) (*node, *Params) {
|
||||
searchParts := filterNonEmpty(strings.Split(path, "/"))
|
||||
n := r.root.search(searchParts, 0)
|
||||
|
||||
if n.path != "" {
|
||||
parts := filterNonEmpty(strings.Split(n.path, "/"))
|
||||
params := &Params{}
|
||||
|
||||
for index, part := range parts {
|
||||
if part[0] == ':' {
|
||||
params.set(part[1:], searchParts[index])
|
||||
}
|
||||
}
|
||||
return n, params
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *router) getRoutes() []*node {
|
||||
list := make([]*node, 0)
|
||||
r.root.travel(&list)
|
||||
return list
|
||||
}
|
||||
|
||||
func filterNonEmpty(vs []string) []string {
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
}
|
||||
}
|
||||
return parts
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newTestRouter() *router {
|
||||
r := &router{root: &node{}}
|
||||
r.addRoute("/", nil)
|
||||
r.addRoute("/hello/:name", nil)
|
||||
r.addRoute("/hello/b/c", nil)
|
||||
r.addRoute("/hi/:name", nil)
|
||||
return r
|
||||
}
|
||||
|
||||
func TestGetRoute(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n, ps := r.getRoute("/a/geektutu")
|
||||
|
||||
fmt.Printf("matched path: %s, params['name']: %s\n", n.path, ps.Get("name"))
|
||||
|
||||
if n == nil {
|
||||
t.Fatal("nil shouldn't be returned")
|
||||
}
|
||||
|
||||
if n.path != "/a/:name" {
|
||||
t.Fatal("should match /a/:name")
|
||||
}
|
||||
|
||||
if ps.Get("name") != "geektutu" {
|
||||
t.Fatal("name should be equal to 'geektutu'")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoutes(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
for i, n := range r.getRoutes() {
|
||||
fmt.Println(i+1, n)
|
||||
}
|
||||
|
||||
if len(r.getRoutes()) != 4 {
|
||||
t.Fatal("the number of routes shoule be 4")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
path string
|
||||
part string
|
||||
children []*node
|
||||
isWild bool
|
||||
handler HandlerFunc
|
||||
}
|
||||
|
||||
func (n *node) String() string {
|
||||
return fmt.Sprintf("node{path=%s, part=%s, isWild=%t}", n.path, n.part, n.isWild)
|
||||
}
|
||||
|
||||
func (n *node) insert(path string, parts []string, handler HandlerFunc, height int) {
|
||||
if len(parts) == height {
|
||||
n.path = path
|
||||
n.handler = handler
|
||||
return
|
||||
}
|
||||
|
||||
part := parts[height]
|
||||
child := n.matchChild(part)
|
||||
if child == nil {
|
||||
child = &node{part: part, isWild: part[0] == ':'}
|
||||
n.children = append(n.children, child)
|
||||
}
|
||||
child.insert(path, parts, handler, height+1)
|
||||
}
|
||||
|
||||
func (n *node) search(parts []string, height int) *node {
|
||||
if len(parts) == height {
|
||||
if n.path == "" {
|
||||
return nil
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
part := parts[height]
|
||||
children := n.matchChildren(part)
|
||||
|
||||
for _, child := range children {
|
||||
result := child.search(parts, height+1)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *node) travel(list *([]*node)) {
|
||||
if n.path != "" {
|
||||
*list = append(*list, n)
|
||||
}
|
||||
for _, child := range n.children {
|
||||
child.travel(list)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) matchChild(part string) *node {
|
||||
for _, child := range n.children {
|
||||
if child.part == part || child.isWild {
|
||||
return child
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *node) matchChildren(part string) []*node {
|
||||
nodes := make([]*node, 0)
|
||||
for _, child := range n.children {
|
||||
if child.part == part || child.isWild {
|
||||
nodes = append(nodes, child)
|
||||
}
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
// $ curl http://localhost:9999/
|
||||
// URL.Path = "/"
|
||||
// $ curl http://localhost:9999/hello
|
||||
// Header["Accept"] = ["*/*"]
|
||||
// Header["User-Agent"] = ["curl/7.54.0"]
|
||||
// curl http://localhost:9999/world
|
||||
// 404 NOT FOUND: /world
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"./gee"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.GET("/", func(w http.ResponseWriter, req *http.Request, params *gee.Params) {
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
|
||||
})
|
||||
|
||||
r.GET("/hello/:name", helloHandler)
|
||||
r.Run(":9999")
|
||||
}
|
||||
|
||||
func helloHandler(w http.ResponseWriter, req *http.Request, params *gee.Params) {
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
|
||||
fmt.Fprintf(w, "Parse params in path, name: %s\n", params.Get("name"))
|
||||
}
|
||||
+4
-4
@@ -62,10 +62,10 @@ func handler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
## 目录
|
||||
|
||||
- 第一天:前置知识(http.Handler接口)
|
||||
- 第二天:Tire树实现路由(Router)
|
||||
- 第三天:支持模板(HTML Template)
|
||||
- 第四天:JSON & RESTful API
|
||||
- [第一天:前置知识(http.Handler接口)](https://geektutu.com/post/gee-day1.html)
|
||||
- [第二天:Tire树实现路由(Router)](https://geektutu.com/post/gee-day2.html)
|
||||
- 第三天:设计Context
|
||||
- 第四天:支持模板(HTML Template)
|
||||
- 第五天:支持中间件(Middleware)
|
||||
- 第六天:简单鉴权(BASIC AUTH)
|
||||
- 第七天:异常错误处理(Panic)
|
||||
|
||||
Reference in New Issue
Block a user