Iris微服务框架

Iris微服务框架,第1张

Iris简介

Iris是一款Go语言中用来开发web应用的框架,该框架支持编写一次并在任何地方以最小的机器功率运行,如Android、ios、Linux和Windows等。该框架只需要一个可执行的服务就可以在平台上运行了。

Iris框架以简单而强大的api而被开发者所熟悉。iris除了为开发者提供非常简单的访问方式外,还同样支持MVC。另外,用iris构建微服务也很容易。

在iris框架的官方网站上,被称为速度最快的Go后端开发框架。在Iris的网站文档上,列出了该框架具备的一些特点和框架特性,列举如下:

Iris特性 专注于高性能简单流畅的API高扩展性强大的路由和中间件生态系统使用iris独特的表达主义路径解释器构建RESTful API动态路径参数化或通配符路由与静态路由不冲突使用重定向选项从URL中删除尾部斜杠使用虚拟主机和子域名变得容易分组API和静态或甚至动态子域名net / http和negroni-like处理程序通过iris.FromStd兼容针对任意Http请求错误 定义处理函数支持事务和回滚支持响应缓存使用简单的函数嵌入资源并与go-bindata 保持兼容mvc上下文高度可扩展的试图渲染(目前支持markdown,json,xml,jsonp等等)正文绑定器和发送HTTP响应的便捷功能限制请求正文提供静态资源或嵌入式资产本地化i18N压缩(Gzip是内置的)身份验证Basic AuthenticationOAuth, OAuth2 (支持27个以上的热门网站)JWT *服务器通过TLS提供服务时,自动安装和提供来自https://letsencrypt.org的证书默认为关闭状态在关闭,错误或中断事件时注册连接多个服务器,完全兼容 net/http#Server视图系统.支持五种模板隐隐 完全兼容 html/templateWebsocket库,其API类似于http://socket.io [如果你愿意,你仍然可以使用你最喜欢的]热重启Typescript集成 + Web IDE

官方源代码地址: https://github.com/kataras/iris

Iris web微服务框架示例

总体功能

集成aiwuTech.fileLogger日志按天切割,按级别输出到不同日志文件集成redis集成mysql读取etcd配置异常处理,全局异常处理拦截器打印请求和响应参数前端html集成等等

下载iris依赖包
go get -u github.com/kataras/iris
main.go项目入口

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)
}


AccessLogMiddleware.go 中间件拦截器

在拦截器中添加请求头
把请求参数和响应参数打印到日志文件

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()))
}


logger.go 日志定义和配置
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)
}


mysql.go mysql初始化连接
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.")
}

redis.go redis初始化和常用 *** 作方法
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)
}

......

handler 注意Iris会自动扫描handler包名

如果分了多个包,像demo里分了user和html,这时iris扫描不到.
需要在handler包中添加一个公共的文件把这2个包导入,如下所示

package handler

import (
	_ "web-demo/handler/html"
	_ "web-demo/handler/user"
)

其他功能就不详细介绍了,请看源代码

web-demo运行
#启动项目
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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/993876.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存