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