路由行为
Iris
默认接受和注册形如/api/user
这样的路径的路由,且尾部不带斜杠。如果客户端尝试访问$your_host/api/user/
,Iris
路由会自动永久重定向(301)到$your_host/api/user
,以便注册的路由进行处理。这是设计APIs的现代化的方式。如果你想禁用请求的
路径更正
的功能的话,你可以在app.Run
传递iris.WithoutPathCorrection
配置选项。例如app.Run(iris.Addr(":8080"),iris.WithoutPathCorrection) //如果向/api/user和/api/user、在不重定向的情况下拥有相同的处理器,只需要`iris.WithoutPathCorrectionRedirection`选项即可 app.Run(iris.Addr(":8080"),iris.WithoutPathCorrectionRedirection)
Api
支持所有的HTTP方法,开发者也可以在相同的路径的不同的方法注册处理器(比如
/user
的Get和POST)第一个参数是HTTP方法,第二个参数是请求的路径,第三个可变参数应包含一个或者多个
iris.Handler
当客户端请求到特定的资源路径时,这些处理器将会按照注册的顺序依次执行。示例代码
app:=iris.New() app.Handle("GET","/contact",func(ctx iris.Context){ ctx.HTML("<h1>hello from /contact</h1>") })
为了让后端开发者做事更容易,
Iris
为所有的HTTP方法提供了"帮手"。第一个参数是路由的请求路径,第二个可变参数是一个或者多个iris.Handler
也会按照顺序依次执行离线路由
在
Iris
中有一个特俗得方法可以使用。它被称为None
.你可以使用它向外部隐藏一条路由,但仍然可以从其他路由处理中通过Context。Exec
方法调用。每个API处理方法返回Route值。一个Route得IsOnline方法报告那个路由的当前状态
。你可以通过它的Route.Method
字段的值来改变路由离线
状态为在线状态
。每次需要调用app.RefreshRouter
方法。package main import ( "github.com/kataras/iris/v12" ) func main() { app := iris.New() //离线路由 none := app.None("/leaveRouter", func(context iris.Context) { context.Writef("hello world %v", context.Method()) }) //app.Get app.Get("/change", func(context iris.Context) { //如果在西安 if none.IsOnline() { none.Method = iris.MethodNone } else { none.Method = iris.MethodGet } }) app.Run(iris.Addr(":8080")) } //先采用 http://localhost:8080/leaveRouter 访问 返回 Not Found //http://localhost:8080/change //http://localhost:8080/leaveRoute hello world GET
路由组
一些列路由可以通过路径的前缀分组。共享相同的中间件处理器和模板布局。一个组也可以有一个内嵌的组
package main import "github.com/kataras/iris/v12" func main() { //初始化 application := iris.New() v1 := application.Party("/v1") v1.Get("/getName", func(context iris.Context) { context.Writef("name:%v", "zhangsan") }) v1.Get("/getAge", func(context iris.Context) { context.Writef("age:%v", 10) }) application.Run(iris.Addr(":8080")) } //http://localhost:8080/v1/getAge //http://localhost:8080/v1/getName 也可以使用PartyFunc方法编写相同的内容,它接受子路由器或者Party package main import "github.com/kataras/iris/v12" func main() { //初始化 application := iris.New() application.PartyFunc("/v1", func(user iris.Party) { user.Get("/getName", func(context iris.Context) { context.Writef("name:%v", "zhangsan") }) user.Get("/getAge", func(context iris.Context) { context.Writef("age:%v", 10) }) }) application.Run(iris.Addr(":8080")) }
路径参数
与你见到的其他路由器不同,Iris的路由器可以处理各种 路由路径而不会发生冲突
//只匹配到/ app.Get("/") //匹配到所有的user/前缀的请求 app.Get("/user/{user:path}) //匹配以profile前缀的GET请求 app.Get("/profile/{username:string}") //匹配profile/me的Get请求 app.Get("/user/{userid:int min(1)}") //匹配前缀为user的delete请求 app.DELETE("/user/{userId:int min(1)}") //除了被其他路由器处理的请求,其他的都可以匹配到 app.Get("{root:path}")
路径参数类型
Iris
拥有你见过的最简单和强大路由处理
Iris
自己拥有于路由路径语法解析和判定的解释器参数
一个路径的参数的名字应该仅仅包含
字母
。数字和类似"_"这样的符号是不允许的
不要迷惑于
ctx.Params()
和ctx.Values()
- 路径的参数值可以通过
ctx.Params()
取出ctx
中用于处理器与中间件之间通信的本地存储可以存储在ctx.Values()
中内建参数类型
参数类型 golang类型 取值范围 取值方式 :string
string
任何值(单个字段路径) Params().Get
:int
int
-9223372036854775808 - 9223372036854775807 (x64) </br>-2147483648 - 2147483647 (x32) Params().GetInt
:int8
int8
-128 - 127 Params().GetInt8
:int16
int16
-32768 - 32767 Params().GetInt16
:int32
int32
-2147483648 - 2147483647 Params().GetInt32
:int64
int64
-9223372036854775808 - 9223372036854775807 Params().GetInt64
:uint8
uint8
0 - 255 Params().GetUint8
:uint16
uint16
0 - 65535 Params().GetUint16
:uint32
uint32
0 - 4294967295 Params().GetUint32
:uint64
uint64
0 - 18446744073709551615 Params().GetUint64
:bool
bool
"1","t","T","TRUE","true","True","0","f", "F", "FALSE",,"false","False" Params().GetBool
:alphabetical
string
小写或大写字母 Params().Get
:file
string
大小写字母,数字,下划线(_),横线(-),点(.),以及没有空格或者其他对文件名无效的特殊字符 Params().Get
:path
string
任何可以被斜线(/)分隔的路径段,但是应该为路由的最后一部分 Params().Get
内建函数
内建函数 参数类型 regexp(expr string)
:string
prefix(prefix string)
:string
suffix(suffix string)
:string
contains(s string)
:string
min(最小值),接收:int,int8,int16,int32,int64,uint8
,uint16,uint32,uint64,float32,float64)
:string(字符长度),:int,:int16,:int32,:int64
,</br>:uint,:uint16,:uint32,:uint64
max(最大值),接收:int,int8,int16,int32,int64,uint8
,uint16,uint32,uint64,float32,float64)
:string(字符长度),:int,:int16,:int32,:int64
,</br>:uint,:uint16,:uint32,:uint64
range(最小值,最大值),接收:int,int8,int16,int32,int64,uint8
,uint16,uint32,uint64,float32,float64)
:int,:int16,:int32,:int64
,</br>:uint,:uint16,:uint32,:uint64
自己做
RegisterFunc可以接受任何返回
func(paramValue string)bool
的函数、如果验证失败则触发404
或者任意else
关键字拥有的状态码package main import ( "fmt" "github.com/kataras/iris/v12" "regexp" ) func main() { //改正则表达式 匹配0次或者1次- //0-9匹配1位到3位 latLonExpr := "^-?[0-9]{1,3}(?:\\.[0-9]{1,10})?$" latLonRegex, _ := regexp.Compile(latLonExpr) app := iris.New() // 将您的自定义无参数宏函数注册到 :string 参数类型。 // MatchString 是 func(string) bool 的一种类型,因此我们按原样使用它。 app.Macros().Get("string").RegisterFunc("coordinate", latLonRegex.MatchString) //http://localhost:8080/coordinates/AAA/BBB 404 NOT found 因为正则表达式全是数字 //http://localhost:8080/coordinates/111/222 通过 app.Get("/coordinates/{lat:string coordinate()}/{lon:string coordinate()}", func(ctx iris.Context) { getString := ctx.Params().GetString("lat") fmt.Println(getString) ctx.Writef("Lat: %s | Lon: %s", ctx.Params().Get("lat"), ctx.Params().Get("lon")) }) app.Run(iris.Addr(":8080")) } //注册接受2个int类型的函数 package main import ( "github.com/kataras/iris/v12" ) func main() { //改正则表达式 匹配0次或者1次- //0-9匹配1位到3位 app := iris.New() //这个函数接受2个数如果这个参数值 大于最小值 小于最大值 则通过 否则400 app.Macros().Get("string").RegisterFunc("range", func(minLength, maxLength int) func(string) bool { return func(paramValue string) bool { return len(paramValue) >= minLength && len(paramValue) <= maxLength } }) //limitchar后面的值在5,200的范围之内 否则400 app.Get("/limitchar/{name:string range(5,200) else 400}", func(ctx iris.Context) { name := ctx.Params().Get("name") ctx.Writef(`Hello %s | the name should be between 1 and 200 characters length otherwise this handler will not be executed`, name) }) app.Run(iris.Addr(":8080")) }
中间件
package main import ( "fmt" "github.com/kataras/iris/v12" ) func main() { //改正则表达式 匹配0次或者1次- //0-9匹配1位到3位 app := iris.New() //这个函数接受2个数如果这个参数值 大于最小值 小于最大值 则通过 否则400 app.Get("/get", before, mainHanlder, after) app.Run(iris.Addr(":8080")) } func before(ctx iris.Context) { fmt.Println("before the main Hanlder") ctx.Next() } func mainHanlder(ctx iris.Context) { fmt.Println("business") ctx.Next() } func after(ctx iris.Context) { fmt.Println("after ") } //result before the main Hanlder business after
处理HTTP错误
自定义处理器处理特定的http错误
func main(){ app:=iris.New() app.OnErrorCode(iris.StatusNotFound,notFound) app.Run(iris.Addr(":8080")) } func notFound(){ ctx.View("errors/404.html") }
问题类型
Iris内建支持HTTP APIs的错误详情
Context.Problem
编写一个JSON或者XML问题响应,行为完全类似Context.JSON
但是默认ProblemOptions.JSON
的缩进是"",响应的Content-Type
为application/problem+json
使用
options.RenderXML
和XML
字段来改变他的行为。用application/problem+xml
的文本类型替代。package main import ( "github.com/kataras/iris/v12" ) func newProductPoblem(productName, detail string) iris.Problem { return iris.NewProblem(). Type("/product-error"). Title("Product validation problem"). Detail(detail). Status(iris.StatusBadRequest). Key("productName", productName) } func main() { app := iris.New() app.Get("/problem", fireProblem) app.Run(iris.Addr(":8080")) } func fireProblem(ctx iris.Context) { ctx.Problem(newProductPoblem("productName", "problem details"), iris.ProblemOptions{ JSON: iris.JSON{ Indent: "", }, // OR // Render as XML: // RenderXML: true, // XML: iris.XML{Indent: " "}, // Sets the "Retry-After" response header. // // Can accept: // time.Time for HTTP-Date, // time.Duration, int64, float64, int for seconds // or string for date or duration. // Examples: // time.Now().Add(5 * time.Minute), // 300 * time.Second, // "5m", // RetryAfter: 300, // A function that, if specified, can dynamically set // retry-after based on the request. // Useful for ProblemOptions reusability. // Overrides the RetryAfter field. // // RetryAfterFunc: func(iris.Context) interface{} { [...] } }) }
API版本控制
go get github.com/kataras/iris/v12/versioning
- 对于每个路由版本匹配,一个普通的iris处理程序,带有"switch"案例通过版本 处理程序的映射
- 每组版本化的路由和启用API
- 版本匹配,例如">=1.0 ,<2.0"或仅仅是"2.0.1"等
- 找不到版本的处理程序(可以通过简单地添加versiong.NotFound)来自定义:customNotMatchVersionHandler在映射上
- 版本是从"Accept"和"Accept-Version"头中检索到地
- 如果版本找到,响应具有
X-API-Version
头- 通过
Deprecated
包装器,弃用了自定义X-API-Warn
,X-API-Deprecation-Data
,X-API-Deprecation-Info
头部的选项获取版本
当前请求的版本通过versiong.GetVersion(ctx)获得
package main import ( "fmt" "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/versioning" ) func main() { app := iris.New() app.Get("/problem", func(context iris.Context) { //获取当前系统的版本号 fmt.Println(versioning.GetVersion(context)) }) app.Run(iris.Addr(":8081")) } //我们可以通过中间件设置自定义版本 func(ctx iris.Context){ ctx.Values().Set(versiong.Key, ctx.URLParamDefault("version", "1.0")) ctx.Next() }
将版本与处理程序匹配
versioning.NewMatcher(versiong.Map)iris.Handler
创建一个简单处理器,这个处理器决定基于请求的版本。哪个处理器需要执行。package main import ( "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/versioning" ) func main() { application := iris.New() myMiddle := func(ctx iris.Context) { ctx.Next() } versionNotFound := func(ctx iris.Context) { ctx.StatusCode(404) ctx.Writef("version %v", versioning.GetVersion(ctx)) } party := application.Party("/version") party.Get("/", myMiddle, versioning.NewMatcher(versioning.Map{ "1.0": func(context iris.Context) { context.Writef("1.0") }, "2.0": func(context iris.Context) { context.Writef("2.0") }, versioning.NotFound: versionNotFound, })) application.Run(iris.Addr(":8081")) } //请求 curl -H "Accept-Version:2" http://localhost:8081/version //2.0 curl -H "Accept-Version:1" http://localhost:8081/version //1.0 curl -H http://localhost:8081/version //not found
弃用
使用
Versioning.Deprecated(handler iris.Handler,options versioning.DeprecationOptions)iris.Handler
函数可以标记特定的处理器版本为被弃用的
package main import ( "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/versioning" "time" ) func main() { application := iris.New() myMiddle := func(ctx iris.Context) { ctx.Next() } versionNotFound := func(ctx iris.Context) { ctx.StatusCode(404) ctx.Writef("version %v", versioning.GetVersion(ctx)) } deprecated := versioning.Deprecated(sendHandler, versioning.DeprecationOptions{ DeprecationDate: time.Now(), }) party := application.Party("/version") party.Get("/", myMiddle, versioning.NewMatcher(versioning.Map{ "1.0": deprecated, "2.0": func(context iris.Context) { context.Writef("2.0") }, versioning.NotFound: versionNotFound, })) application.Run(iris.Addr(":8081")) } func sendHandler(ct iris.Context) { ct.Writef("AAAAAAKKKKKK") }
网友评论