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