路由行为

Iris默认接受和注册形如/api/user这样的路径的路由,且尾部不带斜杠。如果客户端尝试访问$your_host/api/user/,Iris路由会自动永久重定向(301)到$your_host/api/user,以便注册的路由进行处理。这是设计APIs的现代化的方式。

如果你想禁用请求的路径更正的功能的话,你可以在app.Run传递iris.WithoutPathCorrection配置选项。例如

  1. app.Run(iris.Addr(":8080"),iris.WithoutPathCorrection)
  2. //如果向/api/user和/api/user、在不重定向的情况下拥有相同的处理器,只需要`iris.WithoutPathCorrectionRedirection`选项即可
  3. app.Run(iris.Addr(":8080"),iris.WithoutPathCorrectionRedirection)

Api

支持所有的HTTP方法,开发者也可以在相同的路径的不同的方法注册处理器(比如/user的Get和POST)

第一个参数是HTTP方法,第二个参数是请求的路径,第三个可变参数应包含一个或者多个iris.Handler当客户端请求到特定的资源路径时,这些处理器将会按照注册的顺序依次执行。

示例代码

  1. app:=iris.New()
  2. app.Handle("GET","/contact",func(ctx iris.Context){
  3. ctx.HTML("<h1>hello from /contact</h1>")
  4. })

为了让后端开发者做事更容易,Iris为所有的HTTP方法提供了”帮手”。第一个参数是路由的请求路径,第二个可变参数是一个或者多个iris.Handler也会按照顺序依次执行

离线路由

Iris中有一个特俗得方法可以使用。它被称为None.你可以使用它向外部隐藏一条路由,但仍然可以从其他路由处理中通过Context。Exec方法调用。每个API处理方法返回Route值。一个Route得IsOnline方法报告那个路由的当前状态。你可以通过它的Route.Method字段的值来改变路由离线状态为在线状态。每次需要调用app.RefreshRouter方法。

```go 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

  1. > > <a name="14de92d5"></a>
  2. #### 路由组
  3. > 一些列路由可以通过路径的前缀分组。共享相同的中间件处理器和模板布局。一个组也可以有一个内嵌的组
  4. > ```go
  5. package main
  6. import "github.com/kataras/iris/v12"
  7. func main() {
  8. //初始化
  9. application := iris.New()
  10. v1 := application.Party("/v1")
  11. v1.Get("/getName", func(context iris.Context) {
  12. context.Writef("name:%v", "zhangsan")
  13. })
  14. v1.Get("/getAge", func(context iris.Context) {
  15. context.Writef("age:%v", 10)
  16. })
  17. application.Run(iris.Addr(":8080"))
  18. }
  19. //http://localhost:8080/v1/getAge
  20. //http://localhost:8080/v1/getName
  21. 也可以使用PartyFunc方法编写相同的内容,它接受子路由器或者Party
  22. package main
  23. import "github.com/kataras/iris/v12"
  24. func main() {
  25. //初始化
  26. application := iris.New()
  27. application.PartyFunc("/v1", func(user iris.Party) {
  28. user.Get("/getName", func(context iris.Context) {
  29. context.Writef("name:%v", "zhangsan")
  30. })
  31. user.Get("/getAge", func(context iris.Context) {
  32. context.Writef("age:%v", 10)
  33. })
  34. })
  35. application.Run(iris.Addr(":8080"))
  36. }

路径参数

与你见到的其他路由器不同,Iris的路由器可以处理各种 路由路径而不会发生冲突

  1. //只匹配到/
  2. app.Get("/")
  3. //匹配到所有的user/前缀的请求
  4. app.Get("/user/{user:path})
  5. //匹配以profile前缀的GET请求
  6. app.Get("/profile/{username:string}")
  7. //匹配profile/me的Get请求
  8. app.Get("/user/{userid:int min(1)}")
  9. //匹配前缀为user的delete请求
  10. app.DELETE("/user/{userId:int min(1)}")
  11. //除了被其他路由器处理的请求,其他的都可以匹配到
  12. 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)
-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,uint8uint16,uint32,uint64,float32,float64) :string(字符长度),:int,:int16,:int32,:int64
:uint,:uint16,:uint32,:uint64
max(最大值),接收:int,int8,int16,int32,int64,uint8uint16,uint32,uint64,float32,float64) :string(字符长度),:int,:int16,:int32,:int64
:uint,:uint16,:uint32,:uint64
range(最小值,最大值),接收:int,int8,int16,int32,int64,uint8uint16,uint32,uint64,float32,float64) :int,:int16,:int32,:int64
:uint,:uint16,:uint32,:uint64

自己做

RegisterFunc可以接受任何返回func(paramValue string)bool的函数、如果验证失败则触发404或者任意else关键字拥有的状态码

```go 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)

  1. app := iris.New()
  2. // 将您的自定义无参数宏函数注册到 :string 参数类型。
  3. // MatchString 是 func(string) bool 的一种类型,因此我们按原样使用它。
  4. app.Macros().Get("string").RegisterFunc("coordinate", latLonRegex.MatchString)
  5. //http://localhost:8080/coordinates/AAA/BBB 404 NOT found 因为正则表达式全是数字
  6. //http://localhost:8080/coordinates/111/222 通过
  7. app.Get("/coordinates/{lat:string coordinate()}/{lon:string coordinate()}",
  8. func(ctx iris.Context) {
  9. getString := ctx.Params().GetString("lat")
  10. fmt.Println(getString)
  11. ctx.Writef("Lat: %s | Lon: %s", ctx.Params().Get("lat"), ctx.Params().Get("lon"))
  12. })
  13. app.Run(iris.Addr(":8080"))

} //注册接受2个int类型的函数 package main

import ( “github.com/kataras/iris/v12” )

func main() { //改正则表达式 匹配0次或者1次- //0-9匹配1位到3位

  1. app := iris.New()
  2. //这个函数接受2个数如果这个参数值 大于最小值 小于最大值 则通过 否则400
  3. app.Macros().Get("string").RegisterFunc("range", func(minLength, maxLength int) func(string) bool {
  4. return func(paramValue string) bool {
  5. return len(paramValue) >= minLength && len(paramValue) <= maxLength
  6. }
  7. })
  8. //limitchar后面的值在5,200的范围之内 否则400
  9. app.Get("/limitchar/{name:string range(5,200) else 400}", func(ctx iris.Context) {
  10. name := ctx.Params().Get("name")
  11. ctx.Writef(`Hello %s | the name should be between 1 and 200 characters length otherwise this handler will not be executed`, name)
  12. })
  13. app.Run(iris.Addr(":8080"))

}

  1. > > <a name="3cbfec33"></a>
  2. ##### 中间件
  3. > ```go
  4. package main
  5. import (
  6. "fmt"
  7. "github.com/kataras/iris/v12"
  8. )
  9. func main() {
  10. //改正则表达式 匹配0次或者1次-
  11. //0-9匹配1位到3位
  12. app := iris.New()
  13. //这个函数接受2个数如果这个参数值 大于最小值 小于最大值 则通过 否则400
  14. app.Get("/get", before, mainHanlder, after)
  15. app.Run(iris.Addr(":8080"))
  16. }
  17. func before(ctx iris.Context) {
  18. fmt.Println("before the main Hanlder")
  19. ctx.Next()
  20. }
  21. func mainHanlder(ctx iris.Context) {
  22. fmt.Println("business")
  23. ctx.Next()
  24. }
  25. func after(ctx iris.Context) {
  26. fmt.Println("after ")
  27. }
  28. //result
  29. before the main Hanlder
  30. business
  31. after

处理HTTP错误

自定义处理器处理特定的http错误

  1. func main(){
  2. app:=iris.New()
  3. app.OnErrorCode(iris.StatusNotFound,notFound)
  4. app.Run(iris.Addr(":8080"))
  5. }
  6. func notFound(){
  7. ctx.View("errors/404.html")
  8. }

问题类型

Iris内建支持HTTP APIs的错误详情

Context.Problem编写一个JSON或者XML问题响应,行为完全类似Context.JSON但是默认ProblemOptions.JSON的缩进是””,响应的Content-Typeapplication/problem+json

使用options.RenderXMLXML字段来改变他的行为。用application/problem+xml的文本类型替代。

```go 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{} { […] } }) }

  1. > > <a name="4fcf3af7"></a>
  2. ##### API版本控制
  3. >

go get github.com/kataras/iris/v12/versioning

  1. > - 对于每个路由版本匹配,一个普通的iris处理程序,带有"switch"案例通过版本 处理程序的映射
  2. > - 每组版本化的路由和启用API
  3. > - 版本匹配,例如">=1.0 ,<2.0"或仅仅是"2.0.1"
  4. > - 找不到版本的处理程序(可以通过简单地添加versiong.NotFound)来自定义:customNotMatchVersionHandler在映射上
  5. > - 版本是从"Accept""Accept-Version"头中检索到地
  6. > - 如果版本找到,响应具有`X-API-Version`
  7. > - 通过`Deprecated`包装器,弃用了自定义`X-API-Warn``X-API-Deprecation-Data``X-API-Deprecation-Info`头部的选项
  8. > > <a name="3f1e8309"></a>
  9. ##### 获取版本
  10. > 当前请求的版本通过versiong.GetVersion(ctx)获得
  11. > ```go
  12. package main
  13. import (
  14. "fmt"
  15. "github.com/kataras/iris/v12"
  16. "github.com/kataras/iris/v12/versioning"
  17. )
  18. func main() {
  19. app := iris.New()
  20. app.Get("/problem", func(context iris.Context) {
  21. //获取当前系统的版本号
  22. fmt.Println(versioning.GetVersion(context))
  23. })
  24. app.Run(iris.Addr(":8081"))
  25. }
  26. //我们可以通过中间件设置自定义版本
  27. func(ctx iris.Context){
  28. ctx.Values().Set(versiong.Key, ctx.URLParamDefault("version", "1.0"))
  29. ctx.Next()
  30. }

将版本与处理程序匹配

versioning.NewMatcher(versiong.Map)iris.Handler创建一个简单处理器,这个处理器决定基于请求的版本。哪个处理器需要执行。

```go 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

  1. > > <a name="d0b600ac"></a>
  2. ##### 弃用
  3. > 使用`Versioning.Deprecated(handler iris.Handler,options versioning.DeprecationOptions)iris.Handler`函数
  4. > 可以标记特定的处理器版本为被弃用的
  5. > ```go
  6. package main
  7. import (
  8. "github.com/kataras/iris/v12"
  9. "github.com/kataras/iris/v12/versioning"
  10. "time"
  11. )
  12. func main() {
  13. application := iris.New()
  14. myMiddle := func(ctx iris.Context) {
  15. ctx.Next()
  16. }
  17. versionNotFound := func(ctx iris.Context) {
  18. ctx.StatusCode(404)
  19. ctx.Writef("version %v", versioning.GetVersion(ctx))
  20. }
  21. deprecated := versioning.Deprecated(sendHandler, versioning.DeprecationOptions{
  22. DeprecationDate: time.Now(),
  23. })
  24. party := application.Party("/version")
  25. party.Get("/", myMiddle, versioning.NewMatcher(versioning.Map{
  26. "1.0": deprecated,
  27. "2.0": func(context iris.Context) {
  28. context.Writef("2.0")
  29. },
  30. versioning.NotFound: versionNotFound,
  31. }))
  32. application.Run(iris.Addr(":8081"))
  33. }
  34. func sendHandler(ct iris.Context) {
  35. ct.Writef("AAAAAAKKKKKK")
  36. }