Iris是一款Go语言中用来开发web应用的框架,该框架支持编写一次并在任何地方以最小的机器功率运行,如Android、ios、Linux和Windows等。该框架只需要一个可执行的服务就可以在平台上运行了。
Iris框架以简单而强大的api而被开发者所熟悉。iris除了为开发者提供非常简单的访问方式外,还同样支持MVC。另外,用iris构建微服务也很容易。
在iris框架的官方网站上,被称为速度最快的Go后端开发框架。在Iris的网站文档上,列出了该框架具备的一些特点和框架特性,列举如下:
官方源代码地址: https://github.com/kataras/iris
总体功能
go get -u github.com/kataras/iris
init方法: 初始化相关配置,都有注释说明
main方法: 启动Iris服务
package main
import (
. "web-demo/config"
. "web-demo/log"
. "web-demo/redis"
. "web-demo/db"
_ "web-demo/handler"
"web-demo/web"
"flag"
"fmt"
"time"
)
var showVersion = flag.Bool("v", true, "print version")
func init(){
//调用 flag.Parse() 进行解析
flag.Parse()
//初始化配置文件
ConfigRead()
//初始化log日志
LogInit()
//初始化redis
RedisInit(Cfg.RedisAddr,0 , Cfg.RedisPassword, Cfg.RedisMaxConn)
//初始化mysql
SqlDBInit(&SqlDBParam{Cfg.MysqlHost, Cfg.MysqlPort, Cfg.MysqlUser, Cfg.MysqlPwd,
Cfg.MysqlDb})
}
func main() {
if *showVersion {
//这个日期就是写死的一个日期,不是这个日期就不认识,就不能正确的格式化
//据说是go诞生之日
version := fmt.Sprintf("%s %s@%s", "web-demo", "1.0", time.Now().Format("2006-01-02 15:04:05"))
fmt.Println(version)
}
Log.Info("start server...")
//监听端口
Log.Info("listen on :%s", Cfg.ListenPort)
web.RunIris(Cfg.ListenPort)
}
在拦截器中添加请求头
把请求参数和响应参数打印到日志文件
package web
import (
. "web-demo/util/threadlocal"
. "web-demo/log"
"github.com/kataras/iris"
. "github.com/jtolds/gls"
"strconv"
"time"
)
func init() {
RegisterPreMiddleware(accessLogMiddleware{})
}
type accessLogMiddleware struct {
// your 'stateless' fields here
}
func (m accessLogMiddleware) Serve(ctx *iris.Context) {
//check header
//request id
requestId := ctx.RequestHeader("X-Web-Demo-RequestId")
if requestId == "" {
requestId = strconv.FormatInt(time.Now().UnixNano(), 10)
}
//access log
AccessLog.Info(requestId + "\t" + ctx.RequestIP() + "\t" + string(ctx.RequestURI()))
//response requestId
ctx.Response.Header.Add("X-Web-Demo-RequestId", requestId)
//do chian
Mgr.SetValues(Values{Rid: requestId}, func() {
ctx.Next()
})
//rrlog
RRLog.Info(requestId + "\t" + "-RequestIP:==" + ctx.RequestIP())
RRLog.Info(requestId + "\t" + "-RequestP:==" + string(ctx.RequestPath(true)))
RRLog.Info(requestId + "\t" + "-RequestD:==" + string(ctx.Request.Body()))
RRLog.Info(requestId + "\t" + "-Response:==" + string(ctx.Response.Body()))
}
package log
import (
"flag"
"github.com/aiwuTech/fileLogger"
"os"
. "web-demo/util/threadlocal"
"web-demo/config"
)
var Log Logger
var ErrorLog Logger
var AccessLog Logger
var RRLog Logger
var InnerRRLog Logger
type Logger interface {
Trace(format string, params ...interface{})
Info(format string, params ...interface{})
Warn(format string, params ...interface{})
Error(format string, params ...interface{})
}
type CustomedLogger struct{
MyLogger Logger
}
func (cl CustomedLogger)Trace(format string, params ...interface{}){
cl.MyLogger.Trace(cl.resetFormat(format), params)
}
func (cl CustomedLogger)Info(format string, params ...interface{}){
cl.MyLogger.Info(cl.resetFormat(format), params)
}
func (cl CustomedLogger)Warn(format string, params ...interface{}){
cl.MyLogger.Warn(cl.resetFormat(format), params)
}
func (cl CustomedLogger)Error(format string, params ...interface{}){
cl.MyLogger.Error(cl.resetFormat(format), params)
}
func (cl CustomedLogger)resetFormat(format string) string{
logstr := format
if rid, ok := Mgr.GetValue(Rid); ok {
logstr = rid.(string) + " - " + logstr
}
return logstr
}
func LogInit() {
logPath := config.Cfg.LogPath
if (len(logPath) == 0) {
logPath = "/Users/liang/ideaWorkspace/go/src/web-demo/logs/web-demo"
}
flag.Parse()
if !isExist(logPath) {
os.Mkdir(logPath, 0755)
}
logger := fileLogger.NewDailyLogger(logPath, "root.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
Log = CustomedLogger{MyLogger: logger}
errorLog := fileLogger.NewDailyLogger(logPath, "error.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
ErrorLog = CustomedLogger{MyLogger: errorLog}
accessLog := fileLogger.NewDailyLogger(logPath, "access.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
AccessLog = CustomedLogger{MyLogger: accessLog}
rRLog := fileLogger.NewDailyLogger(logPath, "rr.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
RRLog = CustomedLogger{MyLogger: rRLog}
innerRRLog := fileLogger.NewDailyLogger(logPath, "inner_rr.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
InnerRRLog = CustomedLogger{MyLogger: innerRRLog}
}
func isExist(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
package db
import (
. "web-demo/log"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
. "web-demo/config"
)
var Mysql *gorm.DB
type SqlDBParam struct {
Ip string
Port int
User string
Pw string
Database string
}
// mysql初始化文件
func SqlDBInit(param *SqlDBParam) {
Log.Info("init mysql...")
param_s := fmt.Sprintf(
"%v:%v@tcp(%v:%v)/%v?parseTime=True&loc=Local",
param.User,
param.Pw,
param.Ip,
param.Port,
param.Database,
)
Log.Info("mysql param: %s", param_s)
db, err := gorm.Open("mysql", param_s)
if err != nil {
Log.Error("open mysql error: %v", err)
panic(err)
}
db.DB().SetMaxIdleConns(Cfg.MysqlMaxConn)
db.SingularTable(true)
db.LogMode(true)
Mysql = db
Log.Info("init mysql end.")
}
package redis
import (
. "web-demo/log"
"github.com/garyburd/redigo/redis"
"time"
)
var (
redisPool *redis.Pool
)
const (
maxIdle = 500
idleTimeout = 0 * time.Second
wait = true
)
//Init
//eg: RedisInit("127.0.0.1:6379", 0, "pwd", 8)
func RedisInit(server string, db int, password string, maxConn int) {
maxActive := maxConn
//Make a pool object
redisPool = &redis.Pool{
// Maximum number of idle connections in the pool.
MaxIdle: maxIdle,
// Maximum number of connections allocated by the pool at a given time.
// When zero, there is no limit on the number of connections in the pool.
MaxActive: maxActive,
// Close connections after remaining idle for this duration. If the value
// is zero, then idle connections are not closed. Applications should set
// the timeout to a value less than the server's timeout.
IdleTimeout: idleTimeout,
// If Wait is true and the pool is at the MaxActive limit, then Get() waits
// for a connection to be returned to the pool before returning.
Wait: wait,
// Dial is an application supplied function for creating and configuring a
// connection.
//
// The connection returned from Dial must not be in a special state
// (subscribed to pubsub channel, transaction started, ...).
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", server)
if err != nil {
return nil, err
}
if password != "" {
if _, err := c.Do("AUTH", password); err != nil {
c.Close()
return nil, err
}
}
if _, err := c.Do("SELECT", db); err != nil {
c.Close()
return nil, err
}
return c, nil
},
// TestOnBorrow is an optional application supplied function for checking
// the health of an idle connection before the connection is used again by
// the application. Argument t is the time that the connection was returned
// to the pool. If the function returns an error, then the connection is
// closed.
TestOnBorrow: func(c redis.Conn, t time.Time) error {
if time.Since(t) < time.Minute {
return nil
}
_, err := c.Do("PING")
return err
},
}
Log.Info("redis[%v %v] init ok", server, db)
}
......
如果分了多个包,像demo里分了user和html,这时iris扫描不到.
需要在handler包中添加一个公共的文件把这2个包导入,如下所示
package handler
import (
_ "web-demo/handler/html"
_ "web-demo/handler/user"
)
其他功能就不详细介绍了,请看源代码
#启动项目
go run main.go
#打印如下,表示成功启动8080端口
listen on :8080
浏览器访问:
http://127.0.0.1:8080/webdemo/html/v1/passenger/login.md
显示login.md文件内容
http://127.0.0.1:8080/webdemo/html/v1/index
显示index.html内容
Demo源代码地址:https://github.com/golang-example/web-demo