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

原文地址:https://www.cnblogs.com/tomtellyou/p/12874530.html