GoLang Echo 简介

2020-03-05 language golang network

echo web 框架是通过 GoLang 开发的一种高性能、可扩展、轻量级的 web 框架,只包含了 MVC 框架的 C 部分,也就是负责 URL 路由和控制器部分,对于 V 视图和 M 数据操作可以使用自己喜欢的工具库来实现。

这里简单介绍其使用方法。

echo introduce

简介

如下是一个简单的示例。

package main

import (
    "net/http"

    "github.com/labstack/echo"
)

func main() {
    e := echo.New()
    e.GET("/hello", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello World!")
    })
    e.Start(":8080")
}

这里默认使用的是 v3 版本,如果要使用 v4 或者更高版本在导入时需要指定 "github.com/labstack/echo/v4" 或者 "github.com/labstack/echo/v4/middleware" 即可。

路由

Echo 的路由基于 Radix Tree ,它让路由的查询非常快,而且路由使用了 Sync Pool 来重复利用内存并且几乎达到了零内存占用。上述的示例针对 GET 方法,除了单类型之外,还可用 Any() 匹配所有,通过 Match() 匹配多个方法。

匹配路径按照优先级包含了:A) 静态,也就是全路径,例如 /user;B) 参数,在路径中制定参数,例如 /user/:id;C) 匹配,也就是通过星号 * 作为匹配符。

另外比较有用的是 Group() 路由组机制,可以将一些关联的路由绑定,这样就可以统一设置权限、定制中间件等。更多用法可以参考 Routing

使用包

这里使用 GoLang 最新的包管理工具 Modules 来维护升级 echo 框架。

static/         静态文件资源
 |-css/         CSS文件
 |-js/          JS文件
 |-html/
config/         项目配置信息
contrib/        一些常用的脚本、工具等
middleware/     中间件
model/          数据库数据模型
 |-orm/         ORM扩展
module/         模块封装
 |-auth/        Auth授权
 |-cache/       缓存
 |-session/     会话信息

模板

默认不包含关于视图模版的处理,只是提供了集成第三方模版引擎的接口,可以根据自己的需要选择任何第三方模版引擎,通常需要如下三个步骤:

  • 实现 echo.Renderer 接口。
  • 注册模版引擎。
  • 在控制器中渲染模版并返回 html 页面。

如下简单介绍使用。

实现 echo.Renderer 接口

定义的接口如下。

Renderer interface {
	Render(io.Writer, string, interface{}, Context) error
}

通过实现 echo.Renderer 接口自定义当调用 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)
}

注册模板引擎

接下来,需要向 echo 实例注册模版引擎。

e := echo.New()
e.Renderer = &Template{
    templates: template.Must(template.ParseGlob("views/*.html")),
}
e.GET("/hello", Hello)

这里模版引擎支持提前编译模版,会对 views 目录下以 html 结尾的模版文件进行预编译处理,其目的是为了优化后期渲染模版文件的速度。

渲染页面

在路由之后,通过如下方式渲染对应的页面,其中三个参数分别为 HTTP 状态码、模板文件名、模板参数。

func Hello(c echo.Context) error {
    return c.Render(200, "hello.html", "World")
}

其模版文件 views/hello.html 内容为。

Hello, {{.}}!

其它

参数获取

echo 框架提供了 Bind 函数,可以直接将接收到的数据进行转换,提供了 json、xml、表单、URL 等格式的数据转换方式,也可以自己定义。

type user struct {
	UserName string `json:"username" form:"username"`
	Password string `json:"password" form:"password"`
}

func handler(c echo.Context) error {
	u := new(user)
	if err := c.Bind(u); err != nil {
		return err
	}
}

表单

HTML 提供的默认表单,可以使用如下方式。

curl -X POST http://127.1:1323/v1/hello -d 'name=Andy' -d 'email=andy@foobar.com'

在 echo 中可以通过 c.FormValue("name") 获取。

参数

在 URL 中,直接以 ?name=Andy&email=andy@foobar.com 格式提交请求,例如:

curl -X GET 'http://127.1:1323/v1/hello?name=Andy&email=andy@foobar.com'

在 echo 中可以通过 c.QueryParam("name") 获取,或者通过 c.QueryParams() 获取所有参数。

JSON

也就是发送的数据为 JSON 格式。

curl -X POST http://127.1:1323/v1/hello -H 'Content-Type: application/json' \
	-d '{"name":"Andy","email":"andy@foobar.com"}'

可以通过如下方式读取并返回 JSON 数据格式。

msg, err := ioutil.ReadAll(r.Body)
if err != nil {
	return err
}

if len(msg) == 0 {
	return c.String(http.StatusOK, "Hello, World!")
}

var body map[string]interface{}
if err = json.Unmarshal(msg, &body); err != nil {
	return err
}
body["method"] = r.Method
return c.JSON(http.StatusOK, body)

客户端IP地址

有几种获取 IP 地址的方式。

  • X-Real-IP 包含客户端机器的地址,某些代理服务器 (例如 Nginx) 会填充。
  • X-Forwarded-For 一系列 IP 地址列表以 , 分隔,每个经过的代理服务器都会添加一个 IP 地址。
  • RemoteAddr 客户端的真实 IP 地址,也是 Web 服务器从其接收连接并将响应发送到的实际物理 IP 地址,但是如果客户端通过代理连接,它将提供代理的 IP 地址。

也就是说,RemoteAddr 最可靠,但是如果客户端位于代理之后或使用负载平衡器或反向代理服务器时,它将永远不会提供正确的 IP 地址,因此顺序是先是 X-Real-IP,然后是 X-Forwarded-For,最后是 RemoteAddr

注意,恶意用户可以创建伪造的 X-Real-IPX-Forwarded-For 头。

在 echo 中可以通过 context.RealIP() 获取,会通过 IPExtractor 钩子函数调用,可以在开始通过 e.IPExtractor = xxx 修改,支持 echo.ExtractIPFromXFFHeader() echo.ExtractIPDirect() echo.ExtractIPFromRealIPHeader() 等函数,详见 echo IP Address 中的介绍。

参考