Iris微服务框架_golang web框架_完整示例Demo

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 Authentication
  • OAuth, OAuth2 (支持27个以上的热门网站)
  • JWT *服务器
  • 通过TLS提供服务时,自动安装和提供来自https://letsencrypt.org的证书
  • 默认为关闭状态
  • 在关闭,错误或中断事件时注册
  • 连接多个服务器,完全兼容 net/http#Server
  • 视图系统.支持五种模板隐隐 完全兼容 html/template
  • Websocket库,其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://www.mfbz.cn/a/331365.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

寒武纪显卡实现softmax的pingpong流水并行

在上一篇文章添加链接描述中我们介绍了寒武纪显卡实现基本的softmax代码&#xff0c;这里我们借助于寒武纪的流水并行来编写进一步的策略。 pingpongGDRAM2NRAM流水 仅仅计算max和sum使用流水 我们先考虑不使用SRAM的流水&#xff0c;我们设置两个NRAM上的长度为maxNum上的数…

STM32标准库开发——USART串口外设

USART外设介绍 USART (Universal Synchronous/AsynchronousReceiver/Transmitter&#xff09;通用同步/异步收发器USART是STM32内部集成的硬件外设&#xff0c;可根据数据寄存器的一个字节数据自动生成数据帧时序&#xff0c;从TX引脚发送出去&#xff0c;也可自动接收RX引脚的…

WebGL中开发AR应用

WebGL在本质上是用于在浏览器中进行3D和2D图形渲染的技术&#xff0c;而增强现实&#xff08;AR&#xff09;通常需要与现实世界的环境进行交互。要在WebGL中开发AR应用&#xff0c;您可以采取以下步骤&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专…

Arm Generic Interrupt Controller v3 and v4(GICv3v4)学习(一)

提示 该博客主要为个人学习&#xff0c;通过阅读官网手册整理而来&#xff08;个人觉得阅读官网的英文文档非常有助于理解各个IP特性&#xff09;。若有不对之处请参考参考文档&#xff0c;以官网参考文档为准。 Arm Generic Interrupt Controller v3 and v4学习一共分为三章&…

RHEL8 Samba服务器详细配置用户模式

任务&#xff1a; 配置server01为samba服务器&#xff0c;samba服务器的/companydata/sales为共享目录&#xff0c;共享名为sales&#xff0c;里面创建测试文件test_share.tar&#xff0c;创建用户组sales&#xff0c;创建组内用户sale1&#xff0c;要求配置用户模式访问&#…

Uniapp多选Popup(弹出层)

uniapp中多选组件很少&#xff0c;故个人简单开发了一个&#xff0c;可简单使用&#xff0c;也可根据个人需求稍微改进 支持的功能 单选多选&#xff08;默认&#xff09;限制选择数量默认选中禁用选项 属性说明 属性默认值说明singlefalsetrue为开启单选&#xff0c;否则为…

无需信用卡注册美区Apple ID指南

第一步 准备工作 1、一个没有注册过AppleID的邮箱&#xff0c;建议最好是Gmail邮箱 2、一个苹果手机&#xff0c;当然这个是必须的 3、需要科学上网 第二步 苹果网站注册 为了避免cookie的干扰&#xff0c;最好是在无痕模式下打开以上网页&#xff0c;创建你的AppleID&#…

rabbitmq-java基础详解

一、rabbitmq是什么&#xff1f; 1、MQ定义 MQ&#xff08;Message Queue&#xff09;消息队列 主要解决&#xff1a;异步处理、应用解耦、流量削峰等问题&#xff0c;是分布式系统的重要组件&#xff0c;从而实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性的架…

Spring+SpringMVC+Mybatis进行项目的整合

Spring SpringMVCM Mybatis 整合 一、 通过idea创建maven工程 二、 引入依赖项以及导入mybatis逆向工程的插件 将如下的文件替换所在工程的pom文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4…

HCIA的访问控制列表ACL

ACL -----access control-list 允许/拒绝 ACL作用&#xff1a; 1.实现访问控制 2.定义感兴趣流量 ACL分类&#xff1a; 标准ACL 2000-2999&#xff08;只关注源IP地址&#xff0c;使用时应该尽量靠近目标&#xff09; 扩展ACL 3000-3999&#xff1a;写ACL不能写在源上&…

反射计数 - 华为OD统一考试

OD统一考试 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 给定一个包含 0 和 1 的二维矩阵, 给定一个初始位置和速度。 一个物体从给定的初始位置触发, 在给定的速度下进行移动, 遇到矩阵的边缘则发生镜面反射无论物体经过 0 还是 1&#xff0c;都不…

2024美赛数学建模思路 - 案例:异常检测

文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…

宠物空气净化器真的有用吗?五款猫用宠物空气净化器测评!

作为一个养猫四年的铲屎官&#xff0c;我不得不说&#xff0c;宠物空气净化器是21世纪养猫人最伟大的神器之一&#xff01; 当我刚开始养猫的时候&#xff0c;我并没有意识到猫毛会成为一个如此头疼的问题。虽然朋友们告诉我要做好心理准备&#xff0c;但我并没有想到家里的猫毛…

Apache Zeppelin学习记录2

Apache Zeppelin学习记录2 文章目录 Apache Zeppelin学习记录2前言一、基础调用二、带参数调用1.代码块要增加一行z.textbox("folder_path", "input")2.读取result 总结 前言 上一章讲了如何使用zeppelin来接入python&#xff0c;本节我们来看看如何使用R…

ArcGIS初始化软件界面Normal.mxt

ArcGIS有时候永久了&#xff0c;或者呢突然不自觉软件界面乱了&#xff0c;或者一些窗口打开却找不到&#xff01; 这时候可以去删除arcgis的界面配置文件&#xff0c;Normal.mxt 删除后再打开软件&#xff0c;软件界面就会回到初始化设置了&#xff01; 文件所在的路径&…

3d音响按键怎么建立模型---模大狮模型网

要建立3D音响按键的模型&#xff0c;您可以按照以下步骤进行&#xff1a; 选择建模软件&#xff1a;首先&#xff0c;选择一个三维建模软件&#xff0c;如Blender、3ds Max或Maya。这些软件都提供了丰富的建模工具和功能&#xff0c;适合用于创建复杂的三维模型。 参考图像&am…

IPv6自动隧道---ISATAP隧道

ISATAP隧道 ISATAP(Intra-Site Automatic Tunnel Addressing Protocol)是另外一种自动隧道技术。ISATAP隧道同样使用了内嵌IPv4地址的特殊IPv6地址形式,只是和6to4不同的是,6to4是使用IPv4地址做为网络前缀,而ISATAP用IPv4地址做为接口标识。 站点内自动隧道寻址协议(I…

Web Animation API

工作中经常会遇到需要动画的场景&#xff0c;连贯动画都是用CSS实现&#xff0c;&#xff0c;但是如果遇到需要用户互动介入的动画&#xff0c;那纯CSS很比较吃力&#xff0c;也不是不能实现&#xff0c;需要动态修改CSS变量&#xff0c;而且动画容易被JS代码阻塞&#xff0c;导…

VMP比较正确的编译教程

一、编译环境 1.1 编译整体配置 采用VS2022社区版MSVC2017_xpQT5.6.0WDK7.1&#xff08;编译DDK需要&#xff0c;不需要DDK的可以不用下载&#xff09; 1.1 VS2022安装 1.1.1 除常规勾选桌面C以外&#xff0c;需要勾选win xp支持和支持相应的MSVC版本。教程采用msvc2017和x…

​批量文件夹随机小写字母重命名:文件夹重命名简单步骤,高效结果

在日常工作中&#xff0c;经常要对大量的文件夹重命名进行管理和查找文件。手动重命名每个文件夹不仅耗时&#xff0c;而且容易出错。现在一起来看云炫文件管理器如何给文件夹名称批量随机小写字母重命名&#xff0c;简单的步骤&#xff0c;高效率的结果。 文件夹名称随机小写…
最新文章