Golang echo 快速入门教程
一、介绍
echo web框架是go语言开发的一种高性能,可扩展,轻量级的web框架。 echo框架真的非常简单,几行代码就可以启动一个高性能的http服务端。
如果你只是测试返回hello world这种简单逻辑,普通的低配服务器,每秒扛个万八千QPS没什么问题,这个主要跟服务器配置有关,当然实际应用中我们的业务逻辑不会是hello world那么简单,业务不同,系统设计不同吞吐量肯定不一样。
echo框架默认其实只包含了MVC框架的C部分,就是负责url路由和控制器部分。至于V视图部分和M数据操作部分我们可以随意使用自己喜欢的工具库来操作。
二、安装
安装echo包
go get github.com/labstack/echo/v4
三、如何开始一个Http Server。
创建httpserver.go文件,代码如下:
package main
import (
"net/http"
//导入echo包
"github.com/labstack/echo/v4"
)
func main() {
//实例化echo对象。
e := echo.New()
//注册一个Get请求, 路由地址为: /tizi365 并且绑定一个控制器函数, 这里使用的是闭包函数。
e.GET("/tizi365", func(c echo.Context) error {
//控制器函数直接返回一个字符串,http响应状态为http.StatusOK,就是200状态。
return c.String(http.StatusOK, "欢迎访问tizi365.com")
})
//启动http server, 并监听8080端口,冒号(:)前面为空的意思就是绑定网卡所有Ip地址,本机支持的所有ip地址都可以访问。
e.Start(":8080")
}
运行http server
$ go run httpserver.go
通过浏览器访问 http://localhost:8080/tizi365 浏览器会显示: 欢迎访问tizi365.com
echo web框架的代码非常简洁,就几行代码一个http server的主要的初始化工作就搞定了,只要添加自己的业务代码就行。
四、项目结构
通过上面的例子,大家都知道echo大致是怎么使用的,但是实际项目业务功能会很多,我们不可能把所有代码都写在一个go文件里面或者写在一个main入口函数里面;我们需要对项目结构做一些规划,方便维护代码以及扩展。
echo web框没有对项目结构做出限制,我们可以根据自己项目需要自行设计。
这里给出一个典型的MVC框架大致的项目结构的例子,大家可以参考下:
├── conf #项目配置文件目录
│ └── config.toml #大家可以选择自己熟悉的配置文件管理工具包例如:toml、xml等等
├── controllers #控制器目录,按模块存放控制器,必要的时候可以继续划分子目录。
│ ├── food.go
│ └── user.go
├── main.go #项目入口,这里负责echo框架的初始化,注册路由信息,关联控制器函数等。
├── models #模型目录,负责项目的数据存储部分,例如各个模块的Mysql表的读写模型。
│ ├── food.go
│ └── user.go
├── static #静态资源目录,包括Js,css,jpg等等,可以通过echo框架配置,直接让用户访问。
│ ├── css
│ ├── images
│ └── js
├── logs #日志文件目录,主要保存项目运行过程中产生的日志。
└── views #视图模板目录,存放各个模块的视图模板,当然有些项目只有api,是不需要视图部分,可以忽略这个目录
└── index.html
提示:上面给出的项目结构,程序编译打包后代码都编译成一个可执行程序,我们需要把conf,static, logs目录一起打包部署,否则程序会找不到配置文件,静态文件,日志存储目录,后面会有专门的教程介绍go项目的打包。
五、路由&控制器
1.路由
echo框架的路由定义如下:
//定义post请求, url为:/users, 绑定saveUser控制器函数
e.POST("/users", saveUser)
//定义get请求,url模式为:/users/:id (:id是参数,例如: /users/10, 会匹配这个url模式),绑定getUser控制器函数
e.GET("/users/:id", getUser)
//定义put请求
e.PUT("/users/:id", updateUser)
//定义delete请求
e.DELETE("/users/:id", deleteUser)
2.控制器
在echo框架中,控制器是一个函数,我们需要根据业务实现各种控制器函数,控制器函数定义如下:
//控制器函数只接受一个echo.Context上下文参数
//参数:c 是上下文参数,关联了当前请求和响应,通过c参数我们可以获取请求参数,向客户端响应结果。
func HandlerFunc(c echo.Context) error
例子:
// 路由定义:e.GET("/users/:id", getUser)
// getUser控制器函数实现
func getUser(c echo.Context) error {
// 获取url上的path参数,url模式里面定义了参数:id
id := c.Param("id")
//响应一个字符串,这里直接把id以字符串的形式返回给客户端。
return c.String(http.StatusOK, id)
}
六、echo如何获取请求参数
控制获取请求参数的例子:
func getUser(c echo.Context) error {
// 方式1:获取url上的path参数,url模式里面定义了参数:id
id := c.Param("id")
//方式2:获取query参数,例如:/users?username=tizi365&type=2
username := c.QueryParam("username") //值为:"tizi365"
usertype := c.QueryParam("type") //值为:"2"
//方式3:获取post请求的表单参数
username := c.FormValue("username")
usertype := c.FormValue("type")
return c.String(http.StatusOK, "获取参数例子")
}
七、响应请求
echo框架支持以文本、html、Json、xml多种格式的内容形式响应Http请求。
控制器响应请求的例子:
type User struct {
Id int
Username string
}
func getUser(c echo.Context) error {
//方式1: 返回字符串
//以字符串的形式返回,c.String语法:c.String(http状态码,"字符串内容")
return c.String(http.StatusOK, "获取参数例子")
//方式2:返回JSON
//以json字符串的形式返回结果,c.JSON语法: c.JSON(http状态码, 结构体变量)
u := User{2, "tizi365"}
return c.JSON(http.StatusOK, u) //返回结果:{"id":2,"username":"tizi365"}
//方式3: 返回HTML
//以网页形式返回html代码,c.HTML语法: c.HTML(http状态码, "html内容")
html := "<html><head><title>tizi365.com</title></head><body>欢迎访问tizi365.com</body></html>"
//当然实际项目,我们不会这样拼写html代码,太麻烦,我们一会使用模板引擎处理Html代码,然后把结果通过c.HTML返回给客户端就行。
return c.HTML(http.StatusOK, html)
}
八、如何展示静态内容
对于js、css、png、jpg这些静态内容,echo框架通过一个配置就可以实现静态资源的展示。
例子:
e := echo.New()
...忽略其他初始化代码...
//设置静态资源url前缀和目录
//这里设置 /static 为静态资源url的前缀,当前程序运行目录下面的static目录为静态资源目录
e.Static("/static", "static")
//例如:static目录下存在js/index.js文件, 则这个js的url为:/static/js/index.js
echo路由与控制器
一、概述
路由是一个过程,指的是一个http请求,如何找到对应的控制器函数或者叫处理器函数。
控制器函数主要负责执行http请求-响应任务。
提示:根据MVC设计模式,控制器不会把所有的请求-响应任务都干了,控制只是作为一个请求的入口、起到协调(调用各个模块)的作用。例如,调用几个model对象操作数据库,然后调用视图引擎把html结果展示出来。
一个简单的例子:
// 路由定义post请求, url路径为:/users, 绑定saveUser控制器函数
e.POST("/users", saveUser)
// 控制器函数
func saveUser(c echo.Context) error {
username := c.FormValue("username")
username := c.FormValue("username")
//调用model保存数据
html := 调用模板引擎渲染html页面
//以Html页面的形式响应请求
return c.HTML(http.StatusOK, html)
}
二、路由规则
一条路由规则由三部分组成:
-
http请求方法
-
url路径
-
控制器函数
1.http请求方法
常用的http请求方法有下面4种:
-
GET
-
POST
-
PUT
-
DELETE
2.url路径
echo框架,url路径有三种写法:
-
静态url路径
-
带路径参数的url路径
-
带星号(*)模糊匹配参数的url路径
// 例子1, 静态Url路径, 即不带任何参数的url路径
/users/center
/user/101
/food/100
// 例子2,带路径参数的url路径,url路径上面带有参数,参数由冒号(:)跟着一个字符串定义。
// 路径参数值可以是数值,也可以是字符串
//定义参数:id, 可以匹配/user/1, /user/899 /user/xiaoli 这类Url路径
/user/:id
//定义参数:id, 可以匹配/food/2, /food/100 /food/apple 这类Url路径
/food/:id
//定义参数:type和:page, 可以匹配/foods/2/1, /food/100/25 /food/apple/30 这类Url路径
/foods/:type/:page
// 例子3. 带星号(*)模糊匹配参数的url路径
// 星号代表匹配任意路径的意思
//匹配:/foods/1, /foods/200, /foods/1/20, /foods/apple/1
//以/foods/ 开头的所有路径都匹配
/foods/*
3.Url路径匹配顺序
上面列出了三种Url路径的写法,那么如果我们项目里面三种路径都有使用,而且出现一个http请求匹配多种路径的时候,echo框架选择哪个路径呢?
例如:一个http Get请求的路径为 /user/10
同时匹配下面三种url路径定义:
/user/10
/user/:id
/user/*
如果出现上述,一个http请求路径匹配多个定义的url路径,echo框架按下面顺序匹配,先匹配到那个就用那个定义。
-
匹配静态url路径
-
匹配带路径参数的url路径
-
匹配带星号(*)模糊匹配参数的url路径
4.控制器函数
控制器函数定义:
func HandlerFunc(c echo.Context) error
控制器函数接受一个上下文参数,并返回一个错误。 可以通过上下文参数,获取http请求参数,响应http请求。
5.路由定义例子
//实例化echo对象。
e := echo.New()
//定义post请求, url路径为:/users, 绑定saveUser控制器函数
e.POST("/users", saveUser)
//定义get请求,url路径为:/users/:id (:id是参数,例如: /users/10, 会匹配这个url模式),绑定getUser控制器函数
e.GET("/users/:id", getUser)
//定义put请求
e.PUT("/users/:id", updateUser)
//定义delete请求
e.DELETE("/users/:id", deleteUser)
//控制器函数实现
func saveUser(c echo.Context) error {
...忽略实现...
}
func getUser(c echo.Context) error {
...忽略实现...
}
func updateUser(c echo.Context) error {
...忽略实现...
}
func deleteUser(c echo.Context) error {
...忽略实现...
}
提示:实际项目开发中不要把路由定义和控制器函数都写在一个go文件,不方便维护,可以参考第一章的项目结构,规划自己的业务模块。
echo如何处理请求参数
本章介绍几种获取请求参数的方式
1.绑定数据
通过将请求参数绑定到一个struct对象的方式获取数据。这种方式获取请求参数支持json、xml、k/v键值对等多种方式。
下面例子是将请求参数绑定到User struct对象。
// User 结构体定义
type User struct {
Name string `json:"name" form:"name" query:"name"`
Email string `json:"email" form:"email" query:"email"`
}
通过定义struct字段的标签,定义请求参数和struct字段的关系。 下面对User的Name字段的标签进行说明。
struct标签说明:
标签 | 说明 |
---|---|
json:"name" | 支持post请求,数据格式为json格式,并且字段名为name |
form:"name" | 支持post请求,并且参数名为name |
query:"name" | 支持get请求,并且参数名为name |
提示:你可以根据自己的需要选择支持的请求方式和数据类型,例如需要支持xml数据格式,可以这样定义字段标签: xml:"name"
下面看控制器代码:
// Handler
func(c echo.Context) (err error) {
u := new(User)
//调用echo.Context的Bind函数将请求参数和User对象进行绑定。
if err = c.Bind(u); err != nil {
return
}
//请求参数绑定成功后 u 对象就保存了请求参数。
//这里直接将请求参数以json格式显示
//注意:User结构体,字段标签定义中,json定义的字段名,就是User对象转换成json格式对应的字段名。
return c.JSON(http.StatusOK, u)
}
2.获取post请求数据
通过echo.Context对象的FormValue函数可以直接获取post请求参数.
// Handler
func(c echo.Context) error {
//获取name参数
name := c.FormValue("name")
//直接输出name参数
return c.String(http.StatusOK, name)
}
提示:通过FormValue函数获取参数的值,数据类型都是String类型, 如果需要其他类型的数据,需要自己转换数据格式。
3.获取get请求数据
通过echo.Context对象的QueryParam函数可以直接获取get请求参数.
// Handler
func(c echo.Context) error {
//获取name参数, 通过QueryParam获取的参数值也是String类型。
name := c.QueryParam("name")
//直接输出name参数
return c.String(http.StatusOK, name)
})
4.获取path路径参数
通过echo.Context对象的Param获取,url路径参数。
//例子: url路由规则为/users/:name , :name为参数。
e.GET("/users/:name", func(c echo.Context) error {
//获取路径参数:name的值
name := c.Param("name")
//如果请求url为: /users/tizi365 则name的值为tizi365
//Param获取的值也是String类型
return c.String(http.StatusOK, name)
})
echo如何处理请求结果
本章介绍处理完http请求后如何响应请求(就是怎么返回处理结果),echo框架支持以字符串、json、xml、文件等格式响应请求。
echo.Context 上下文对象支持多种返回处理结果,下面分别介绍不同的响应方式。
1.以字符串方式响应请求
函数定义: String(code int, s string) error
参数说明:
参数 | 说明 |
---|---|
code | http状态码 |
s | 返回结果 |
例子:
func(c echo.Context) error {
//http.StatusOK == 200
return c.String(http.StatusOK, "欢迎访问tizi360.com!")
//也可以直接设置http状态码
//return c.String(200, "欢迎访问tizi360.com!")
}
提示: net/http包定义了多种常用的状态码常量,例如:http.StatusOK == 200, http.StatusMovedPermanently == 301, http.StatusNotFound == 404等,具体可以参考net/http包
2.以json格式响应请求
函数定义: JSON(code int, i interface{}) error
参数说明:
参数 | 说明 |
---|---|
code | http状态码 |
i | 返回结果对象,通常传入struct对象 |
例子:
// User 定义
type User struct {
Name string `json:"name"` // 通过json标签定义struct字段转换成json字段的名字。
Email string `json:"email"`
}
// Handler 控制器
func(c echo.Context) error {
//初始化user对象
u := &User{
Name: "tizi365",
Email: "tizi@tizi365.com",
}
//返回json数据
//返回结果:{"name":"tizi365", "email":"tizi@tizi365.com"}
return c.JSON(200, u)
}
3.以xml格式响应请求
函数定义: XML(code int, i interface{}) error
参数说明:
参数 | 说明 |
---|---|
code | http状态码 |
i | 返回结果对象,通常传入struct对象 |
例子:
// User 定义, 默认struct的名字就是xml的根节点名字,这里转换成xml后根节点的名字为User.
type User struct {
Name string `xml:"name"` // 通过xml标签定义struct字段转换成xml字段的名字。
Email string `xml:"email"`
}
// Handler 控制器
func(c echo.Context) error {
//初始化user对象
u := &User{
Name: "tizi365",
Email: "tizi@tizi365.com",
}
//返回json数据
//返回结果:
// <?xml version="1.0" encoding="UTF-8"?>
// <User><name>tizi365</name><email>tizi@tizi365.com</email></User>
return c.XML(200, u)
}
4.以文件格式响应请求
如果我们需要实现文件下载功能,可以直接返回文件。 echo支持多种方式返回文件:
例子1:
func(c echo.Context) error {
//通过File函数,直接返回本地文件,参数为本地文件地址。
//函数说明:c.File("文件路径")
return c.File("/var/www/1.jpg")
}
例子2:
func(c echo.Context) error {
//通过Attachment函数,返回本地文件,类似File函数,区别是可以指定下载的文件名。
//函数说明: c.Attachment("文件路径", "下载的文件名")
return c.Attachment("/var/www/1.jpg", "1.jpg")
}
例子3:
func(c echo.Context) (err error) {
data := []byte(`0306703,0035866,NO_ACTION,06/19/2006
0086003,"0005866",UPDATED,06/19/2006`)
//通过Blob函数,以二进制数据格式返回文件
//函数说明:c.Blob(状态码, "contentType", byte数组)
return c.Blob(http.StatusOK, "text/csv", data)
}
例子4:
func(c echo.Context) error {
//打开文件
f, err := os.Open("/var/www/1.jpg")
if err != nil {
return err
}
//通过Stream函数,以stream流的方式返回文件
//函数说明:
//Stream(code int, contentType string, r io.Reader) error
//参数说明:
// code - 状态码
// contentType - html内容类型
// r - 实现io.Reader接口的struct对象都可以直接输出内容
return c.Stream(http.StatusOK, "image/png", f)
}
5.设置http响应头(设置Header)
func(c echo.Context) error {
//设置http响应 header
c.Response().Header().Add("tizi", "tizi365")
return c.String(200, "欢迎访问tizi360.com!")
}
echo html模板处理
Golang echo默认并不包含关于视图模版的处理,只是提供了集成第三方模版引擎的接口。我们可以根据自己的需要选择任何第三方模版引擎。
提示:如果你开发的是接口服务,不提供html页面可以跳过本章内容。
前置技术知识点:
-
模板引擎 - 点击Go模板引擎教程,学习完整的模板引擎语法。
在echo中使用第三方模版引擎至少需要如下三个步骤:
-
实现echo.Renderer接口
-
注册模版引擎
-
在控制器中渲染模版并返回html页面
下面以go自带的html/template模版引擎为例介绍如何使用模版引擎。
1.实现echo.Renderer接口
我们先看下echo.Renderer接口定义:
Renderer interface {
//渲染函数定义
//第一参数用于保存渲染模版后的结果
//第二个参数是模版名字
//第三个参数是传入模版的参数,可以是任意类型
//第四个参数是echo.Context
Render(io.Writer, string, interface{}, Context) error
}
通过实现echo.Renderer接口自定义当调用Render函数的时候我们使用什么模版引擎来渲染模版。
//自定义的模版引擎struct
type Template struct {
templates *template.Template
}
//实现接口,Render函数
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
//调用模版引擎渲染模版
return t.templates.ExecuteTemplate(w, name, data)
}
2.注册模版引擎
接下来,我们需要向echo实例注册模版引擎
//初始化echo实例
e := echo.New()
//初始化模版引擎
t := &Template{
//模版引擎支持提前编译模版, 这里对views目录下以html结尾的模版文件进行预编译处理
//预编译处理的目的是为了优化后期渲染模版文件的速度
templates: template.Must(template.ParseGlob("views/*.html")),
}
//向echo实例注册模版引擎
e.Renderer = t
//初始化路由和控制器函数
e.GET("/hello", Hello)
3.在控制器中渲染模版并返回html页面
完成模版引擎设置后,就可以在控制器函数中通过echo.Context对象的Render函数渲染模版并返回html页面. 函数定义: Render(code int, name string, data interface{}) error
参数说明:
参数 | 说明 |
---|---|
code | http状态码 |
name | 模版文件名 |
data | 模版参数,可以是任意类型数据 |
例子: 模版文件views/hello.html内容
Hello, {{.}}!
渲染模版文件
func Hello(c echo.Context) error {
//渲染hello.html模版文件,模版参数为world
return c.Render(200, "hello.html", "World")
}
渲染结果为:Hello, world!
echo如何访问静态资源文件
echo如何处理js、css、jpg之类的静态文件,怎么访问访问静态文件? echo通过static中间件支持静态资源文件的访问。
我们可以通过echo.Static函数初始化static中间件。
echo.Static函数定义: Static(prefix, root string) *Route
参数说明:
参数 | 说明 |
---|---|
prefix | 静态资源url绑定的url前缀 |
root | 静态资源根目录, . 代表当前目录 |
例子:
//初始化echo实例
e := echo.New()
//设置Static中间件
e.Static("/res", "static")
根据这个例子的设置,如果我们访问 /res/tizi.jpg这个url路径,实际上就是访问static/tizi.jpg这个路径的内容(即访问static目录下面tizi.jpg文件)
我们也可以通过Echo.File函数为一个url地址绑定一个静态资源文件。
例子:
//初始化echo实例
e := echo.New()
//访问 / 就是访问public/index.html文件, index.html相当于站点默认首页
e.File("/", "public/index.html")
//访问/favicon.ico 就是访问images/favicon.ico文件, 相当于为站点设置了图标
e.File("/favicon.ico", "images/favicon.ico")
golang echo 如何处理cookie
在echo框架中,我们可以通过net/http包的Cookie结构体初始化一个cookie,然后通过echo.Context上下文对象的SetCookie函数往请求结果设置cookie.
说明:cookie通常用于在浏览器中保存一些小数据,例如客户标识、用户非铭感数据。注意别使用cookie保存隐私数据。
1.设置cookie
往客户设置一个cookie需要两个步骤:
-
初始化http.Cookie对象
-
调用SetCookie函数设置cookie对象
例子:
// Handler
func(c echo.Context) (err error) {
//初始化cookie对象
cookie := new(http.Cookie)
cookie.Name = "tizi-domain"
cookie.Value = "tizi365.com"
cookie.Path = "/"
//cookie有效期为3600秒
cookie.MaxAge = 3600
//设置cookie
c.SetCookie(cookie)
return c.String(http.StatusOK, "cookie操作")
}
2.http.Cookie结构体定义
这里介绍下http.Cookie有什么字段,大家可以根据需要设置。
type Cookie struct {
Name string //cookie名字
Value string //cookie的值
Path string // [可选字段] cookie路径
Domain string // [可选字段] cookie作用域
Expires time.Time // [可选字段] cookie什么时候失效,需要设置一个具体的失效时间跟MaxAge字段二选一即可,
// MaxAge=0 忽略MaxAge属性.
// MaxAge<0 相当于删除cookie, 通常可以设置-1代表删除
// MaxAge>0 多少秒后cookie失效
MaxAge int // [可选字段] cookie有效期,单位是秒
Secure bool // [可选字段] cookie secure属性
HttpOnly bool // [可选字段] cookie http only属性
}
3.读取cookie
读取cookie主要通过echo.Context上下文对象的Cookie函数进行操作。 例子:
// Handler
func(c echo.Context) (err error) {
//根据cookie名,获取cookie, cookie存在则返回http.Cookie结构体
cookie, err := c.Cookie("tizi-domain")
if err != nil {
return err
}
//打印cookie名
fmt.Println(cookie.Name)
//打印cookie值
fmt.Println(cookie.Value)
return c.String(http.StatusOK, "cookie操作")
}
下面介绍如何一次性查询所有cookie:
// Handler
func(c echo.Context) (err error) {
//通过c.Cookies函数,查询所有cookie
//这里通过循环语句打印所有cookie的名字和值
for _, cookie := range c.Cookies() {
fmt.Println(cookie.Name)
fmt.Println(cookie.Value)
}
return c.String(http.StatusOK, "cookie操作")
}
4.删除cookie
删除cookie本质上是通过设置cookie的过期时间无效,让cookie立刻失效。 例子:
// Handler
func(c echo.Context) (err error) {
//初始化cookie对象
cookie := new(http.Cookie)
//删除cookie只需要设置cookie名字就可以
cookie.Name = "tizi-domain"
//cookie有效期为-1秒,注意这里不能设置为0,否则不会删除cookie
cookie.MaxAge = -1
//设置cookie
c.SetCookie(cookie)
return c.String(http.StatusOK, "cookie操作")
}
golang echo如何处理session
如果我们需要处理用户登录会话,就需要相关的session处理机制,echo框架的session处理是通过中间件实现的。 使用session的关键步骤:
-
导入依赖包
-
设置session中间件
-
读写session数据
1.导入依赖包
导入包之前先安装依赖包
go get github.com/gorilla/sessions
go get github.com/labstack/echo-contrib/session
导入包:
import (
"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数据
下面以网站用户登录为例子介绍如何保存会话数据和读取会话数据。
3.1.用户登录并记录会话数据的例子
这里忽略html登录页面部分,下面直接描述控制器代码大概怎么写。
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, "密码不正确!")
}
})
3.2.获取用户会话数据
3.1.登录成功后,可以通过下面的方式读取用户会话数据
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)
})
golang echo处理文件上传
本章介绍echo如何处理文件上传。 在控制器中主要通过echo.Context上下文对象的FormFile函数获取用户上传的文件。
1.服务端代码
package main
import (
"fmt"
"io"
"net/http"
"os"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
)
//处理上传文件的控制器
func upload(c echo.Context) error {
//-----------
// 介绍演示如何处理文件上传
//-----------
// 通过FormFile函数获取客户端上传的文件
file, err := c.FormFile("file")
if err != nil {
return err
}
//打开用户上传的文件
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()
// 创建目标文件,就是我们打算把用户上传的文件保存到什么地方
// file.Filename 参数指的是我们以用户上传的文件名,作为目标文件名,也就是服务端保存的文件名跟用户上传的文件名一样
dst, err := os.Create(file.Filename)
if err != nil {
return err
}
defer dst.Close()
// 这里将用户上传的文件复制到服务端的目标文件
if _, err = io.Copy(dst, src); err != nil {
return err
}
return c.HTML(http.StatusOK, fmt.Sprintf("<p>文件上传成功: %s</p>", file.Filename))
}
func main() {
e := echo.New()
//设置静态资源中间件, public目录保存静态资源
e.Static("/", "public")
// 注册路由
e.POST("/upload", upload)
e.Logger.Fatal(e.Start(":1323"))
}
2.html视图代码
文件名:public/index.html
提示: 在本地创建一个public目录, 保存index.html代码。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Single file upload</title>
</head>
<body>
<h1>上传文件演示</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
文件: <input type="file" name="file"><br><br>
<input type="submit" value="上传文件">
</form>
</body>
</html>
golang echo中间件
在echo框架中中间件(Middleware)指的是可以拦截http请求-响应生命周期的特殊函数,在请求-响应生命周期中可以注册多个中间件,每个中间件执行不同的功能,一个中间执行完再轮到下一个中间件执行。
下图是中间件的运行流程:
中间件的常见应用场景如下:
-
请求限速
-
api接口签名处理
-
权限校验
-
统一错误处理
提示:如果你想拦截所有请求做一些事情都可以开发一个中间件函数去实现。
1.常用中间件
下面介绍echo自带的中间件
1.1. Redirect
重定向中间件支持下面几种重定向机制:
-
http强制跳转至https 例子: 访问http://www.tizi365.com 自动跳转到https://www.tizi365.com
e := echo.New()
e.Pre(middleware.HTTPSRedirect())
-
www跳转 例子: 访问http://tizi365.com 自动跳转到http://www.tizi365.com
e := echo.New()
e.Pre(middleware.WWWRedirect())
-
https www跳转 例子: 访问http://tizi365.com 自动跳转到https://www.tizi365.com
e := echo.New()
e.Pre(middleware.HTTPSWWWRedirect())
1.2. Recover
Recover中间件,主要用于拦截panic错误并且在控制台打印错误日志,避免echo程序直接崩溃。 使用例子:
//初始化echo实例
e := echo.New()
//注册中间件
e.Use(middleware.Recover())
提示:一般echo应用都会注册Recover中间件,避免程序崩溃退出。
1.3. Static
Static中间件主要用于处理js、css之类的静态资源, 具体用法请参考: 处理静态文件。
1.4. Logger
Logger中间件主要用于打印http请求日志。 例子:
//初始化echo实例
e := echo.New()
//注册中间件
e.Use(middleware.Logger())
开启Logger中间件后,访问http请求会打印下面日志:
{"time":"2017-01-12T08:58:07.372015644-08:00","remote_ip":"::1","host":"localhost:1323","method":"GET","uri":"/","status":200,"error":"","latency":14743,"latency_human":"14.743µs","bytes_in":0,"bytes_out":2}
1.5. Rewrite
url重定向中间,我们可以用于将一个url重定向到另外一个url。 例子:
//初始化echo实例
e := echo.New()
e.Pre(middleware.Rewrite(map[string]string{
"/old": "/new", //将/old重定向至/new
"/api/*": "/$1",
"/js/*": "/public/javascripts/$1",
"/users/*/orders/*": "/user/$1/order/$2",
}))
""星代表任意字符串,$1 代表引用表达式中第一个星()的匹配值, $2代表第二个,以此类推。
1.6. Session
会话中间件,请参考echo session处理章节。
2.自定义中间件
下面以一个简单的统计访问量的例子介绍如何自定义中间件。
package main
import (
"net/http"
"github.com/labstack/echo"
)
//记录访问量
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)
}
}
func main() {
//初始化echo实例
e := echo.New()
//注册中间件
e.Use(Count)
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}
Golang echo 获取IP地址
没有代理的情况
获取客户IP地址如下
e.GET("/tizi365", func(c echo.Context) error {
ip := echo.ExtractIPDirect()(c.Request())
})
有代理的情况
HTTP服务前面使用了负载均衡之类的代理,可以通过X-Forwarded-For
头获取客户真实IP。
e.GET("/tizi365", func(c echo.Context) error { // 获取IP地址 ip := echo.ExtractIPFromXFFHeader()(c.Request()) })