ECHO是golang的一款轻量级的web框架,如同python里的flask,非常灵活,可扩展性很强。
安装
go get github.com/labstack/echo/...
一个简单的hello
func main() {
//创建一个ECHO服务实例
e := echo.New()
//ECHO里的URL路由以及对应的url处理函数
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, ECHO!")
})
//在1323号端口开启服务
e.Logger.Fatal(e.Start(":1323"))
}
在终端启动服务
go run Hello.go
现在打开浏览器访问 127.0.0.1:1323 就能看到返回的字符串 Hello, ECHO! 了。
web框架的核心就是接收http请求,然后进行处理,之后再返回响应。
ECHO的URL路由接收三个参数,一个URLpath,一个是HandlerFunc类型的处理函数,还有一个是中间件。
看一个例子
func getUser(c echo.Context) error {
// User ID 来自于url users/:id
id := c.Param(“id”)
return c.String(http.StatusOK, id)
}
func main() {
e := echo.New()
e.GET("/users/:id", getUser)
…
}
ECHO中的HandlerFunc类型只要是带有(c echo.Cintext) error 签名即可。函数只要携带这个参数,就可以视为HandlerFunc类型,就能当作url处理器。 (个人粗浅看法,这里留一个疑问,在net/http包里,是要实现了ServerHTTP(http.ResponseWriter,*http.Request)
方法才能算得上是一个处理器)
HandlerFunc类型接收上下文参数返回状态码+需要返回的数据或错误。
在net/http包中,可以显示声明一个ServerMux路由,如果不声明,那么使用默认的
ServerMux,在ECHO中,直接echo.GET/PUT/POST/DELETE 就是一个ServerMux
处理请求
echo.Context为url请求上下文,包含了很多url参数信息,可以进行提取
就像python django里的view里面的每个函数都要有一个request参数一样。
Param() :获取url路径里的参数
//http://127.0.0.1:8080/user/1
id := c.Param(“id”)
QueryParam() :获取请求参数
//http://127.0.0.1:8080/get?name=jack&age=12
name := c.QueryParam(“name”)
age := c.Queryparam(“age”)
Formvalue() :获取表单里提交的值
// name bob
// age 18
name := FormValue(“name”)
age := FormValue(“age”)
FormFile(“文件名”): 获取表单上传的文件
name jessic
age 12
avatar avatar //这是一部电影的封面图片文件
上传文件处理流程
代码如下:
//这个func1函数放在最前面,就不用每次打开一个文件或其他都在后面写一句
if err != nil {
return err
}
了。
defer func1() {
if err := recover();err != nil {
fmt.Println(err)
}
}()
//获取avatar对象
avatar ,err := c.FormFile(“avatar”)
//打开资源文件
src ,err := avatar.Open()
defer src.Close()
//在服务器端新建一个同名文件 os.Create(“文件名”)
dst ,err := os.Create(avatar.Filename)
defer dst.Close()
//将传入的文件复制到新建的文件内 io.Copy()
_, err := io.Copy(dst, src)
//将第二个参数的内容复制到第一个文件里面去。
返回响应
请求经过HandlerFunc类型的函数处理过后,就会返回响应,ECHO支持多种响应的返回
return c.String/HTML/XML/JSON()
这些返回都有一个共同点,第一个参数为状态码,可以直接写数字,或者用预定义的常量http.StatusOk (这个值为200)
第二个参数才为函数对应的返回格式内容
如
c.String(200,”hello,Echo”)
c.HTML(200,”hello, Echo
”)
c.JSON(200,json_file)
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) //新建一个结构体实例,可以当作JSON类型
if err := c.Bind(u); err != nil {
return err
}
return c.JSON(http.StatusCreated, u)
// 或者
// return c.XML(http.StatusCreated, u)
})
静态文件处理
既然是web服务,那么少不了静态文件的处理。ECHO提供了两种方法
echo.File()/Static()
Echo.File()为一对一,用于那些静态的的路径
e.File(“/”,”public/index.html”)
e.File(“/favicon.ico”, "images/favicon.ico")
echo.Static(“/”,”目录”) 该方法指定一个目录,将所有经过的符合第一个参数的请求路径都去访问第二个参数指定的目录
如 e.Static("/static", “mystatic”) 表示所有访问http://127.0.0.1:8080/static/文件名 的请求都将访问mystatic目录。
http://127.0.0.1:8080/static/jquery.js 将匹配mystatic/jquery.js
实例
我们的静态文件都放在static下面,然后路由器设置为
e.Static(“/static”, “static”)
这样我们就可以用 http://127.0.0.1:8080/static/js/jquery.js 访问存放在static下的js下的js文件了
有点将二者化为等号的意思。
模版渲染
即将动态数据渲染到静态html页面里
Context#Render(code int, name string, data interface{}) error 用于渲染一个模板,然后发送一个 text/html 的状态响应
c.Render(200, 模版名,数据map),将map里的数据渲染到模版里,并返回200
流程
1.要想能够被渲染,那么模版文件就必须得实现echo.Render接口才行
type Template struct {
templates *template.Template
}
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
return t.templates.ExecuteTemplate(w, name, data)
}
2.将模版先编译
t := &Template{
templates: template.Must(template.ParseGlob("public/views/*.html")),
}
3.注册模版
即将编译好的模版,赋值给echo.Renderer
e := echo.New()
e.Renderer = t
e.GET("/hello", Hello)
4.完成渲染
func Hello(c echo.Context) error {
return c.Render(http.StatusOK, "hello", "World")
}
使用中间件
中间件的定义,有很多种解释
如何让一个函数或方法变成中间件?
只要某个方法实现http.Handler接口即可,跟url处理方法的实现一样,都要实现ServerHTTP(http.ResponseWriter,*http.Request)
建立一个handler链,使其能够满足中间件的 handler 和 正常应用的 handler,并且能够注册到 http.ServeMux
例子
func middlewareOne(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("Executing middlewareOne")
next.ServeHTTP(w, r)
log.Println("Executing middlewareOne again")
})
}
ECHO使用中间件,
E := echo.New()
E.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
if username == "zhangjie" && password == "password" {
return true, nil
}
return false, nil
}))
小记: