Echo框架


Echo框架

1.請求參數的獲取

(1.)路徑參數獲取

e.GET("/users/:id", getUser)

id := c.Param("id")

(2.)查詢參數獲取

/show?team=x-men&member=wolverine 
  
team := c.QueryParam("team")
member := c.QueryParam("member")

(3.)Form表單元素獲取

name := c.FormValue("name")
avatar, err := c.FormFile("avatar")

(4.) JSON請求綁定

type User struct {
	Name  string `json:"name" xml:"name" form:"name" query:"name"`
	Email string `json:"email" xml:"email" form:"email" query:"email"`
}

e.POST("/users", func(c echo.Context) error {
	u := new(User)
    //調用echo.Context的Bind函數將請求參數和User對象進行綁定。
	if err := c.Bind(u); err != nil {
		return err
	}
    //請求參數綁定成功后 u 對象就保存了請求參數。
    //這里直接將請求參數以json格式顯示
    //注意:User結構體,字段標簽定義中,json定義的字段名,就是User對象轉換成json格式對應的字段名。
	return c.JSON(http.StatusCreated, u)
})

2.響應返回

(1.)字符串返回
c.String語法:
c.String(http狀態碼,"字符串內容")

c.String(http.StatusOK, "xxx")

(2.) JSON方式返回
c.JSON語法:
c.JSON(http狀態碼, 結構體變量)

// 通過json標簽定義struct字段轉換成json字段的名字。
type User struct {
    ID int `json:"id"`
    Name string `json:"name"`
}

u := User{2, "zhangsan"}
c.JSON(http.StatusOK, u) //返回結果:{"id":2,"username":"zhangsan"}

//格式化json輸出
c.JSONPretty(http.StatusOK, u, "  ")

// 也可以用json stream方式,不推薦
json.NewEncoder(c.Response()).Encode(u)

//外部json
encodedJSON := []byte{} // Encoded JSON from external source
return c.JSONBlob(http.StatusOK, encodedJSON)

(3.)HTML方式返回
c.HTML語法:
c.HTML(http狀態碼, "html內容")

c.HTML(http.StatusOK, html)

(4.)通過文件格式響應
方式一:
// 通過File函數,直接返回本地文件,參數為本地文件地址。
// 函數說明:c.File("文件路徑")

 c.File("/var/www/1.jpg")

方式二:
//通過Attachment函數,返回本地文件,類似File函數,區別是可以指定下載的文件名。
//函數說明: c.Attachment("文件路徑", "下載的文件名")

c.Attachment("/var/www/1.jpg", "1.jpg")

方式三:
//通過Blob函數,以二進制數據格式返回文件
//函數說明:c.Blob(狀態碼, "contentType", byte數組)

data := []byte(`0306703,0035866,NO_ACTION,06/19/20060086003,"0005866",UPDATED,06/19/2006`)
c.Blob(http.StatusOK, "text/csv", data)

方式四:
//通過Stream函數,以stream流的方式返回文件
//函數說明:
//Stream(code int, contentType string, r io.Reader) error
//參數說明:
// code - 狀態碼
// contentType - html內容類型
// r - 實現io.Reader接口的struct對象都可以直接輸出內容

 //打開文件
f, err := os.Open("/var/www/1.jpg")
c.Stream(http.StatusOK, "image/png", f)

(5.)設置響應頭

 c.Response().Header().Add("name", "zhangsan")

3.靜態資源展示

(1.)靜態資源的展示

e := echo.New()
// 設置 /static 為靜態資源url的前綴,當前程序運行目錄下面的static目錄為靜態資源目錄
e.Static("/static", "static")

//訪問 / 就是訪問public/index.html文件, index.html相當於站點默認首頁
e.File("/", "public/index.html")

(2.)URL的顯示

靜態url路徑 : /users/center
帶路徑參數的url路徑 : /user/:id
帶星號(*)模糊匹配參數的url路徑 : /foods/*  

//匹配任意路徑
Echo.Any(path string, h Handler)
//匹配指定方法的路徑
Echo.Match(methods []string, path string, h Handler)

(3.)控制器函數
控制器函數接受一個上下文參數,並返回一個錯誤。可以通過上下文參數,獲取http請求參數,響應http請求。

func HandlerFunc(c echo.Context) error

(4.)路由分組

g := e.Group("/admin")
g.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
	if username == "joe" && password == "secret" {
		return true, nil
	}
	return false, nil
}))

(5.)路由命名
每一個路由注冊方法都會返回一個路由對象,可以給這個路由對象起個名

route := e.POST("/users", func(c echo.Context) error {
})
route.Name = "create-user"

// or using the inline syntax
e.GET("/users/:id", func(c echo.Context) error {
}).Name = "get-user"

(6.)列出所有路由信息

// Routes
e.POST("/users", createUser)
e.GET("/users", findUser)


// 獲取所有的路由信息
data, _ := json.MarshalIndent(e.Routes(), "", "  ")

// 將路由信息寫入到json文件
ioutil.WriteFile("routes.json", data, 0644)

//routes.json 輸出結果如下
[
  {
    "method": "POST",
    "path": "/users",
    "name": "main.createUser"
  },
  {
    "method": "GET",
    "path": "/users",
    "name": "main.findUser"
  },
]

4.Cookie的操作

(1.)設置cookie

// 初始化cookie對象
cookie := new(http.Cookie)
cookie.Name = "xxx-domain"
cookie.Value = "xxx.com"
cookie.Path = "/"
// cookie有效期為3600秒
cookie.MaxAge = 3600

// 設置cookie
c.SetCookie(cookie)

(2.)獲取cookie

// 根據cookie名,獲取cookie, cookie存在則返回http.Cookie結構體
cookie, err := c.Cookie("xxx-domain")

//打印cookie名
fmt.Println(cookie.Name)
//打印cookie值
fmt.Println(cookie.Value)

(3.)刪除cookie

// 初始化cookie對象
cookie := new(http.Cookie)
// 刪除cookie只需要設置cookie名字就可以
cookie.Name = "xxx-domain"
//cookie有效期為-1秒,注意這里不能設置為0,否則不會刪除cookie
cookie.MaxAge = -1

//設置cookie
c.SetCookie(cookie)

5.Session處理

(1.)導入對應的包

  "github.com/gorilla/sessions"
  "github.com/labstack/echo-contrib/session"

(2.)設置session中間件

//初始化echo實例
e := echo.New()

//設置session數據保存目錄
sessionPath := "./session_data"

//設置cookie加密秘鑰, 可以隨意設置
sessionKey = "Onxuh20a2ihhh2"

//設置session中間件
//這里使用的session中間件,session數據保存在指定的目錄
e.Use(session.Middleware(sessions.NewFilesystemStore(sessionPath, []byte(sessionKey))))

(3.)讀寫session數據
a.用戶登錄並記錄會話數據

e.POST("/login", func(c echo.Context) error {
    //獲取登錄請求參數
    username := c.FormValue("username")
    password := c.FormValue("password")
	
	//校驗帳號密碼是否正確	
    if username == "tizi365" && password == "123456" {
		//密碼正確, 下面開始注冊用戶會話數據
		//以user_session作為會話名字,獲取一個session對象
		sess, _ := session.Get("user_session", c)
		
		//設置會話參數
		sess.Options = &sessions.Options{
            Path:     "/",  //所有頁面都可以訪問會話數據
            MaxAge:   86400 * 7,   //會話有效期,單位秒
        }
        
        //記錄會話數據, sess.Values 是map類型,可以記錄多個會話數據
        sess.Values["id"] = username
        sess.Values["isLogin"] = true
        
        //保存用戶會話數據
        sess.Save(c.Request(), c.Response())
        
		return c.String(200, "登錄成功!")
	} else {
		return c.String(200, "密碼不正確!")
	}
})

b.登錄成功后,可以通過下面的方式讀取用戶會話數據

e.POST("/home", func(c echo.Context) error {
    //以user_session作為會話名字,獲取一個session對象
    //注意這里的session名字,必須跟登錄注冊的會話名字一致
	sess, _ := session.Get("user_session", c)
	
	//通過sess.Values讀取會話數據
	username := sess.Values["id"]
	isLogin  := sess.Values["isLogin"]
	
	//打印會話數據
	fmt.Println(username)
	fmt.Println(isLogin)
})

5.上傳文件

func upload(c echo.Context) error {
	// 通過FormFile函數獲取客戶端上傳的文件
	file, _ := c.FormFile("file")
	
	//打開用戶上傳的文件
	src, _ := file.Open()
	defer src.Close()

	// 創建目標文件,就是我們打算把用戶上傳的文件保存到什么地方
	// file.Filename 參數指的是我們以用戶上傳的文件名,作為目標文件名,也就是服務端保存的文件名跟用戶上傳的文件名一樣
	dst, _ := os.Create(file.Filename)
	
	defer dst.Close()

	// 這里將用戶上傳的文件復制到服務端的目標文件
    io.Copy(dst, src)

	return c.HTML(http.StatusOK, fmt.Sprintf("<p>文件上傳成功: %s</p>", file.Filename))
}

6.中間件

(1.)重定向機制

// http強制跳轉至https
e := echo.New()
e.Pre(middleware.HTTPSRedirect()) //路由之前執行

// www跳轉,訪問 http://xxx.com  --> http://www.xxx.com
e.Pre(middleware.WWWRedirect())

//https+www跳轉 http://xxx.com  --> https://www.xxx.com
e.Pre(middleware.HTTPSWWWRedirect())

// Rewrite 用於將一個url重定向到另外一個url。
// "*"星代表任意字符串,$1 代表引用表達式中第一個星(*)的匹配值, $2代表第二個,以此類推。
e.Pre(middleware.Rewrite(map[string]string{
  "/old":              "/new",   //將/old重定向至/new
  "/api/*":            "/$1",    
  "/js/*":             "/public/javascripts/$1",
  "/users/*/orders/*": "/user/$1/order/$2",
}))

(2.)Recover中間件
主要用於攔截panic錯誤並且在控制台打印錯誤日志,避免echo程序直接崩潰。

//初始化echo實例
e := echo.New()

//注冊中間件
e.Use(middleware.Recover())

(3.)日志中間件
Logger中間件主要用於打印http請求日志。

//初始化echo實例
e := echo.New()

//注冊中間件
e.Use(middleware.Logger())

(4.)自定義中間件

// 初始化echo實例
e := echo.New()
// 注冊中間件
e.Use(Count)

//記錄訪問量
var totalRequests  = 0
//中間件函數
func Count(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		//在這里處理攔截請求的邏輯
		//累計訪問量
		totalRequests++
		
		//在響應頭中輸出訪問量
		c.Response().Header().Add("requests", fmt.Sprintf("%d", totalRequests))

		//執行下一個中間件或者執行控制器函數, 然后返回執行結果
		return next(c)
	}
}

(5.)跳過中間件

e := echo.New()
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
	Skipper: func(c echo.Context) bool {
		if strings.HasPrefix(c.Request().Host, "localhost") {
			return true
		}
		return false
	},
}))

(6.)鑒權中間件

e.Use(middleware.BasicAuthWithConfig(middleware.BasicAuthConfig{}))
// 默認配置
DefaultBasicAuthConfig = BasicAuthConfig{
	Skipper: DefaultSkipper,
}

(7.)請求和響應的攔截

e.Use(middleware.BodyDump(func(c echo.Context, reqBody, resBody []byte) {
}))

(8.)最大請求限制

e.Use(middleware.BodyLimit("2M"))

(9.)Casbin權限控制

enforcer, err := casbin.NewEnforcer("casbin_auth_model.conf", "casbin_auth_policy.csv")
e.Use(casbin_mw.Middleware(enforcer))

(10.)跨域訪問的中間件

e := echo.New()
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
  AllowOrigins: []string{"https://labstack.com", "https://labstack.net"},
  AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},
 AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
}))

(11.)路由追蹤中間件

package main
import (
    "github.com/labstack/echo-contrib/jaegertracing"
    "github.com/labstack/echo/v4"
    "net/http"
    "time"
)
func main() {
    e := echo.New()
    // Enable tracing middleware
    c := jaegertracing.New(e, nil)
    defer c.Close()
    e.GET("/", func(c echo.Context) error {
        // Wrap slowFunc on a new span to trace it's execution passing the function arguments
		jaegertracing.TraceFunction(c, slowFunc, "Test String")
        return c.String(http.StatusOK, "Hello, World!")
    })
    e.Logger.Fatal(e.Start(":1323"))
}

// A function to be wrapped. No need to change it's arguments due to tracing
func slowFunc(s string) {
	time.Sleep(200 * time.Millisecond)
	return
}

7.錯誤處理

(1.)返回http錯誤

//日志記錄
c.Logger().Error(err)
//返回錯誤
echo.NewHTTPError(http.StatusUnauthorized, "Please provide valid credentials")

8.入參校驗

package main

import (
	"github.com/go-playground/validator"
	"github.com/labstack/echo/v4"
	"net/http"
)

type (
	User struct {
		Name  string `json:"name" validate:"required"`
		Email string `json:"email" validate:"required,email"`
	}

	CustomValidator struct {
		validator *validator.Validate
	}
)

func (cv *CustomValidator) Validate(i interface{}) error {
	return cv.validator.Struct(i)
}

func main() {
	e := echo.New()
	e.Validator = &CustomValidator{validator: validator.New()}
	e.POST("/users", func(c echo.Context) (err error) {
		u := new(User)
		if err = c.Bind(u); err != nil {
			return
		}
		if err = c.Validate(u); err != nil {
			return
		}
		return c.JSON(http.StatusOK, u)
	})
	e.Logger.Fatal(e.Start(":1323"))
}

8.Echo框架添加跨域訪問

e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
		AllowOrigins: []string{"*"},
		AllowHeaders: []string{"X-Requested-With", "Content-Type", "Origin", "Authorization", "Accept", "Client-Security-Token", "Accept-Encoding"},
		AllowMethods: []string{echo.GET, echo.PUT, echo.POST, echo.DELETE},
	}))

9.echo文件下載

// 讀取文件內容
fileData, _ := ioutil.ReadFile(uploadPath)
// 獲取文件名
fileName := path.Base(uploadPath)
// 防止中文亂碼
fileName = url.QueryEscape(fileName) 
// 將文件名返回到響應頭中
c.Response().Header().Set(echo.HeaderContentDisposition, "attachment; filename="+fileName)
返回文件流
return c.Stream(http.StatusOK, echo.MIMEOctetStream, bytes.NewReader(fileData))

相關鏈接

https://www.tizi365.com/archives/73.html
https://echo.labstack.com/guide/context


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM