Iris - 路由(1)

Iris 2019-12-17 5667 字 1449 浏览 点赞

起步

上一节总体说了 Iris 的路由、视图、中间件、模板,掌握了快速搭建 web 服务的基本技能。这一节将更深入路由相关知识。

简易的 API

相比于 func (api *APIBuilder) Get(relativePath string, handlers ...context.Handler) *Route其实 Iris 有暴露更底层的接口,也就 Handle

func main() {
    app := iris.Default()
    // 允许跨域访问
    app.Use(func(ctx iris.Context) {
        ctx.Header("Access-Control-Allow-Origin", "*")
        ctx.Next()
    })

    // 注册 path = "/" 的 Get 方法
    app.Handle("GET", "/", func(ctx iris.Context) {
        ctx.HTML("This is Index")
    })
    // 注册 path = "/hername" 的 Post 方法
    app.Handle("POST", "/hername", func(ctx iris.Context) {
        name := ctx.FormValue("name")
        ctx.JSON(iris.Map{
            "herName": name,
        })
    })

    app.Run(iris.Addr(":8080"))
}

Handle 接收三个参数,第一个是 http 请求方式,第二个是 http path,最后一个是 handler 函数

打开 chrome 浏览器控制台,可键入以下代码测路由是否注册成功。

// 验证 path = "/" GET
fetch("http://0.0.0.0:8080/").then(resp => resp.text()).then(data => console.log(data))

// 验证 path = "/hername" POST
let f = new FormData()
f.append("name", "zhong")
fetch("http://0.0.0.0:8080/hername", {method: "POST", body:f}).then(resp => resp.json()).then(data => console.log(data))

而为方便起见,Iris 提供了更易用的上层接口,并满足各种 http 请求方式的需求。

app := iris.New()

// Method: "GET"
app.Get("/", handler)

// Method: "POST"
app.Post("/", handler)

// Method: "PUT"
app.Put("/", handler)

// Method: "DELETE"
app.Delete("/", handler)

// Method: "OPTIONS"
app.Options("/", handler)

// Method: "TRACE"
app.Trace("/", handler)

// Method: "CONNECT"
app.Connect("/", handler)

// Method: "HEAD"
app.Head("/", handler)

// Method: "PATCH"
app.Patch("/", handler)

// register the route for all HTTP Methods
app.Any("/", handler)

func handler(ctx iris.Context){
    ctx.Writef("Hello from method: %s and path: %s\n", ctx.Method(), ctx.Path())
}

默认行为

对一个 http 的 url 来说,末尾要不要加上 / 总是傻傻分不清。Iris 的处理干净利落,认为一切不需要加末尾斜线。如果客户端访问了 $your_host/api/user/,那么默认重定向到 $your_host/api/user

当然,你也可以选择关闭这种默认行为:

func main() {
    app := iris.Default()
    app.Get("/api/user", func(ctx iris.Context) {
        // handle request
    })
    // 关闭 path 的修复功能
    app.Run(iris.Addr(":8080"), iris.WithoutPathCorrection)
}

此时,访问 /api/user 与访问 /api/user/ 的效果就有所不同了。

离线路由(Offline Routes)

离线路由是指,无法从外界访问这个 router,但你可以从其他 router 中借助 Context.Exec 方法访问。具体实现方式是:

func main() {
    app := iris.Default()

    // 注册离线路由
    app.None("/hername", func(ctx iris.Context) {
        ctx.HTML("zhong")
    })
    // 在 router 中调用离线路由
    app.Get("/", func(ctx iris.Context) {
        ctx.Exec("NONE", "/hername")
    })

    app.Run(iris.Addr(":8080"))
}

现在访问 http://127.0.0.1:8080/hername 页面报 404,访问 http://127.0.0.1:8080 页面展示“zhong”。

借助离线路由,我们就可以动态控制一个 url 能否被外界直接访问。完整实例如下:

func main() {
    app := iris.Default()

    // 注册离线路由
    none := app.None("/hername", func(ctx iris.Context) {
        ctx.HTML("zhong")
    })

    app.Get("/change", func(ctx iris.Context) {
        var notifyString string
        if none.IsOnline() {
            // 如果在线就设置为离线
            none.Method = iris.MethodNone
            notifyString = "将 /hername 设置为离线"
        } else {
            // 如果离线就设置为在线
            none.Method = iris.MethodGet
            notifyString = "将 /hername 设置为在线,Get 访问"
        }
        // 运行时刷新路由
        app.RefreshRouter()
        ctx.HTML(notifyString)
    })

    app.Get("/", func(ctx iris.Context) {
        if none.IsOnline() {
            // 如果 /hername 在线,Get 方式请求
            ctx.Exec("GET", "/hername")
        } else {
            // 如果 /hername 离线,None 方式请求
            ctx.Exec("NONE", "/hername")
        }
    })

    app.Run(iris.Addr(":8080"))
}
  • Router.IsOnline() 用于检测 router 是否在线。
  • app.RefreshRouter() 可以运行时刷新 router 的状态。
  • Router.Method 赋值可改变其 router 的 http 请求方法,但调用app.RefreshRouter()后才能生效。

运行上述代码,不论 http://127.0.0.1/hername处于离线还是在线,访问http://127.0.0.1都能成功调用 /hername 的处理逻辑。通过访问 http://127.0.0.1/change 可改变 /hername 的访问状态。

分组路由(Grouping Routes)

路由可通过相同的 path 前缀进行分组,同一组路由可共享一个中间件以及模板。

具体使用示例:

func main() {
    app := iris.Default()

    // 如果想为 grouping routes 添加组件
    // 其方式是:app.Party("user", MyMiddleware, ...)
    user := app.Party("user")
    user.Get("/id", func(ctx iris.Context) {
        ctx.HTML("user id")
    })
    user.Get("/name", func(ctx iris.Context) {
        ctx.HTML("user name")
    })

    app.Run(iris.Addr(":8080"))
}

其效果等同于 app.PartyFunc

func main() {
    ... 
    app.PartyFunc("/user", func(user iris.Party) {
        user.Get("/id", func(ctx iris.Context) {
            ctx.HTML("user id")
        })
        user.Get("/name", func(ctx iris.Context) {
            ctx.HTML("user name")
        })
    })
    ...
}

路径参数(Path Parameters)

一般我把 url 的路径参数称之为 url 位置传参。Iris 提供的 path params 用法与 Flask 相似,简单也强大。简单在于,在 url 路径中,将 param 用花括号包起来即可,如/user/{name};强大则是,它支持类型限制,支持内嵌函数,对检验器(validation)还能自定义。

func main() {
    ...
    // 当不对参数指定类型时,默认为 string 类型
    // 即: "/user/{name}" 等同于 "/user/{name:int}"
    app.Get("/user/{name}", func(ctx iris.Context) {
        // 借助 ctx.Params() 暴露出来的端口,获取参数对应的值
        str := fmt.Sprintf("Hello, %s", ctx.Params().GetString("name"))
        ctx.HTML(str)
    })

    // 指定 id 为 int 型,并且要求 id 的值 > 10000
    app.Get("/userid/{id:int min(1000)}", func(ctx iris.Context) {
        // GetInt16Default("id", 1000)) 表示如果没有 id 键的存在,则返回 1000
        str := fmt.Sprintf("Your id is %d", ctx.Params().GetInt16Default("id", 1000))
        ctx.HTML(str)
    })
    ...
}
  • 此时访问 http://127.0.0.1:8080/userid/999(404) 与 http://127.0.0.1:8080/userid/1000效果大不同。

以上就是 path 的简单应用。而受篇幅原因,关于 Iris 的 path params 更多知识将在下一节中继续阐述。

感谢



本文由 Guan 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论