linux生成mux节点,mux - 路由

[TOC]

> [参考文档](https://github.com/gorilla/mux)

## 安装`

`go get -u github.com/gorilla/mux`

## 实例

### path 解析

```

r := mux.NewRouter()

r.HandleFunc("/products/{key}", ProductHandler)

r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)

r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)

func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {

vars := mux.Vars(r)

w.WriteHeader(http.StatusOK)

fmt.Fprintf(w, "Category: %v\n", vars["category"])

}

```

### 链式匹配

```

//在NewRouter 进行链式调用

r := mux.NewRouter()

// Only matches if domain is "www.example.com".

r.Host("www.example.com")

// Matches a dynamic subdomain.

r.Host("{subdomain:[a-z]+}.example.com")

//在handle 中链式调用

r.HandleFunc("/products", ProductsHandler).

Host("www.example.com").

Methods("GET", "POST").

Schemes("http").

Queries("key", "value")

```

### 子路由

```

r := mux.NewRouter()

s := r.PathPrefix("/products").Subrouter()

s.HandleFunc("/", ProductsHandler)

s.HandleFunc("/{key}/", ProductHandler)

s.HandleFunc("/{key}/details", ProductDetailsHandler)

```

### 静态文件

```

func main() {

var dir string

flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")

flag.Parse()

r := mux.NewRouter()

// This will serve files under http://localhost:8000/static/

r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))

srv := &http.Server{

Handler: r,

Addr: "127.0.0.1:8000",

// Good practice: enforce timeouts for servers you create!

WriteTimeout: 15 * time.Second,

ReadTimeout: 15 * time.Second,

}

log.Fatal(srv.ListenAndServe())

}

```

### 单页面应用

main.go

```

package main

import (

"encoding/json"

"log"

"net/http"

"os"

"path/filepath"

"time"

"github.com/gorilla/mux"

)

type spaHandler struct {

staticPath string

indexPath string

}

func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

path, err := filepath.Abs(r.URL.Path)

if err != nil {

http.Error(w, err.Error(), http.StatusBadRequest)

return

}

path = filepath.Join(h.staticPath, path)

_, err = os.Stat(path)

if os.IsNotExist(err) {

http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath))

return

} else if err != nil {

http.Error(w, err.Error(), http.StatusInternalServerError)

return

}

http.FileServer(http.Dir(h.staticPath)).ServeHTTP(w, r)

}

func main() {

router := mux.NewRouter()

router.HandleFunc("/api/health", func(w http.ResponseWriter, r *http.Request) {

json.NewEncoder(w).Encode(map[string]bool{"ok": true})

})

spa := spaHandler{staticPath: "build", indexPath: "index.html"}

router.PathPrefix("/").Handler(spa)

srv := &http.Server{

Handler: router,

Addr: "127.0.0.1:8000",

WriteTimeout: 15 * time.Second,

ReadTimeout: 15 * time.Second,

}

log.Fatal(srv.ListenAndServe())

}

```

### 生成url

实例1

```

// 给 handle 取名为 article

r := mux.NewRouter()

r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).

Name("article")

// 生成url

url, err := r.Get("article").URL("category", "technology", "id", "42")

// /articles/technology/42

```

实例2

```

r := mux.NewRouter()

r.Host("{subdomain}.example.com").

Path("/articles/{category}/{id:[0-9]+}").

Queries("filter", "{filter}").

HandlerFunc(ArticleHandler).

Name("article")

// url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla"

url, err := r.Get("article").URL("subdomain", "news",

"category", "technology",

"id", "42",

"filter", "gorilla")

```

### 优雅关闭

main.go

```

package main

import (

"context"

"flag"

"log"

"net/http"

"os"

"os/signal"

"time"

"github.com/gorilla/mux"

)

func main() {

var wait time.Duration

flag.DurationVar(&wait, "graceful-timeout", time.Second*15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m")

flag.Parse()

r := mux.NewRouter()

srv := &http.Server{

Addr: "0.0.0.0:8080",

WriteTimeout: time.Second * 15,

ReadTimeout: time.Second * 15,

IdleTimeout: time.Second * 60,

}

go func() {

if err := srv.ListenAndServe(); err != nil {

log.Println(err)

}

}()

c := make(chan os.Signal, 1)

signal.Notify(c, os.Interrupt)

ctx, cancel := context.WithTimeout(context.Background(), wait)

defer cancel()

srv.Shutdown(ctx)

log.Println("shutting down")

os.Exit(0)

}

```

### 中间件

实例1

```

func loggingMiddleware(next http.Handler) http.Handler {

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

// Do stuff here

log.Println(r.RequestURI)

// Call the next handler, which can be another middleware in the chain, or the final handler.

next.ServeHTTP(w, r)

})

}

r := mux.NewRouter()

r.HandleFunc("/", handler)

r.Use(loggingMiddleware)

```

实例2

```

// Define our struct

type authenticationMiddleware struct {

tokenUsers map[string]string

}

// Initialize it somewhere

func (amw *authenticationMiddleware) Populate() {

amw.tokenUsers["00000000"] = "user0"

amw.tokenUsers["aaaaaaaa"] = "userA"

amw.tokenUsers["05f717e5"] = "randomUser"

amw.tokenUsers["deadbeef"] = "user0"

}

// Middleware function, which will be called for each request

func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

token := r.Header.Get("X-Session-Token")

if user, found := amw.tokenUsers[token]; found {

// We found the token in our map

log.Printf("Authenticated user %s\n", user)

// Pass down the request to the next middleware (or final handler)

next.ServeHTTP(w, r)

} else {

// Write an error and stop the handler chain

http.Error(w, "Forbidden", http.StatusForbidden)

}

})

}

r := mux.NewRouter()

r.HandleFunc("/", handler)

amw := authenticationMiddleware{}

amw.Populate()

r.Use(amw.Middleware)

```

### 跨域请求 CORS Requests

main.go

```

package main

import (

"net/http"

"github.com/gorilla/mux"

)

func main() {

r := mux.NewRouter()

// IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers

r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions)

r.Use(mux.CORSMethodMiddleware(r))

http.ListenAndServe(":8080", r)

}

func fooHandler(w http.ResponseWriter, r *http.Request) {

w.Header().Set("Access-Control-Allow-Origin", "*")

if r.Method == http.MethodOptions {

return

}

w.Write([]byte("foo"))

}

```

### handle 测试

测试1

endpoints.go

```

package main

func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {

// A very simple health check.

w.Header().Set("Content-Type", "application/json")

w.WriteHeader(http.StatusOK)

// In the future we could report back on the status of our DB, or our cache

// (e.g. Redis) by performing a simple PING, and include them in the response.

io.WriteString(w, `{"alive": true}`)

}

func main() {

r := mux.NewRouter()

r.HandleFunc("/health", HealthCheckHandler)

log.Fatal(http.ListenAndServe("localhost:8080", r))

}

```

endpoints_test.go

```

package main

import (

"net/http"

"net/http/httptest"

"testing"

)

func TestHealthCheckHandler(t *testing.T) {

// Create a request to pass to our handler. We don't have any query parameters for now, so we'll

// pass 'nil' as the third parameter.

req, err := http.NewRequest("GET", "/health", nil)

if err != nil {

t.Fatal(err)

}

// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.

rr := httptest.NewRecorder()

handler := http.HandlerFunc(HealthCheckHandler)

// Our handlers satisfy http.Handler, so we can call their ServeHTTP method

// directly and pass in our Request and ResponseRecorder.

handler.ServeHTTP(rr, req)

// Check the status code is what we expect.

if status := rr.Code; status != http.StatusOK {

t.Errorf("handler returned wrong status code: got %v want %v",

status, http.StatusOK)

}

// Check the response body is what we expect.

expected := `{"alive": true}`

if rr.Body.String() != expected {

t.Errorf("handler returned unexpected body: got %v want %v",

rr.Body.String(), expected)

}

}

```

测试2

endpoints.go

```

func main() {

r := mux.NewRouter()

// A route with a route variable:

r.HandleFunc("/metrics/{type}", MetricsHandler)

log.Fatal(http.ListenAndServe("localhost:8080", r))

}

```

endpoints_test.go

```

func TestMetricsHandler(t *testing.T) {

tt := []struct{

routeVariable string

shouldPass bool

}{

{"goroutines", true},

{"heap", true},

{"counters", true},

{"queries", true},

{"adhadaeqm3k", false},

}

for _, tc := range tt {

path := fmt.Sprintf("/metrics/%s", tc.routeVariable)

req, err := http.NewRequest("GET", path, nil)

if err != nil {

t.Fatal(err)

}

rr := httptest.NewRecorder()

// Need to create a router that we can pass the request through so that the vars will be added to the context

router := mux.NewRouter()

router.HandleFunc("/metrics/{type}", MetricsHandler)

router.ServeHTTP(rr, req)

// In this case, our MetricsHandler returns a non-200 response

// for a route variable it doesn't know about.

if rr.Code == http.StatusOK && !tc.shouldPass {

t.Errorf("handler should have failed on routeVariable %s: got %v want %v",

tc.routeVariable, rr.Code, http.StatusOK)

}

}

}

```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值