add day1 & day2 code

This commit is contained in:
gzdaijie
2019-08-12 00:55:02 +08:00
parent 34085caadc
commit 8032757a56
12 changed files with 405 additions and 9 deletions
+2 -1
View File
@@ -1 +1,2 @@
.DS_Store
.DS_Store
tmp
+4 -4
View File
@@ -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)
+31
View File
@@ -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)
}
}
+36
View File
@@ -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))
}
+37
View File
@@ -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)
}
}
+31
View File
@@ -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")
}
+52
View File
@@ -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)
}
}
+49
View File
@@ -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
}
+46
View File
@@ -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")
}
}
+82
View File
@@ -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
}
+31
View File
@@ -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
View File
@@ -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)