NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
## 处理程序类型 处理程序, 顾名思义,处理请求。 一个处理程序响应一个 HTTP 请求。它将回复标头和数据写入 `Context.ResponseWriter()`函数,然后返回它们。返回信号表明请求已完成; 在 `Handler` 调用完成之后或与之同时使用 `Context` 是无效的。 根据 HTTP 客户端软件,HTTP 协议版本,及客户端和 iris 服务之间的任何中介结构, 可能无法在写入 `Context.Request().Body` 之后从 `Context.ResponseWriter()` 函数中读取内容。谨慎的处理程序,应首先读取 `Context.Request().Body`,然后进行答复它们。 除了读取正文,处理程序不应修改提供的 `Context`。 如果 `Handler` 出现紧急情况,则服务器(`Handler`的调用方)将假定紧急情况的影响与活动请求无关。它恢复了紧急状态,将堆栈跟踪记录到服务器错误日志中并中断了连接。 ``` type Handler func(iris.Context) ``` 注册处理程序后,我们可以使用返回的 [`路由`](https://godoc.org/github.com/kataras/iris/core/router#Route) 实例为该实例命名处理程序注册,以便于调试或匹配视图中的相对路径。 有关更多信息,请查看 [反向查询](https://github.com/kataras/iris/wiki/Routing-reverse-lookups) 部分。 ## [行为](https://github.com/kataras/iris/wiki/Routing#behavior) Iris 的默认行为是接受和注册像 `/api/user` 这类路径的路由,而且路径末端不带斜杠。如果客户端尝试访问 `$your_host/api/user/` ,则 Iris 路由器将自动将其重定向到 `$your_host/api/user`,以便由注册路由处理它。这是设计 API 的现代方法。 但是,假如你想要对请求的资源 **禁用路径校正**, 你可以传递 iris [配置](https://github.com/kataras/iris/wiki/Configuration)的 `iris.WithoutPathCorrection` 选项到 `app.Run` 函数。 例如: ``` // [app := iris.New...] // [...] app.Run(iris.Addr(":8080"), iris.WithoutPathCorrection) ``` 如果想为`/api/user` 和 `/api/user/`路径,保持相同的处理程序和路由**而无需重定向**(常见情况) ,那么仅仅使用 `iris.WithoutPathCorrectionRedirection` 选项即可: ```source-go app.Run(iris.Addr(":8080"), iris.WithoutPathCorrectionRedirection) ``` ## [API](https://github.com/kataras/iris/wiki/Routing#api) 所有的 HTTP 方法都是被支持的,开发者也可以在相同的路径上注册不同的方法。 第一个参数是 HTTP 方法,第二个参数是路由的请求路径,第三个可变参数应包含一个或多个 `iris.Handler`,当客户端从客户端请求该特定资源路径时,这些 `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.Handler` 将会按照注册顺序执行。 示例代码: ``` app := iris.New() // 方法: "GET" app.Get("/", handler) // 方法: "POST" app.Post("/", handler) // 方法: "PUT" app.Put("/", handler) // 方法: "DELETE" app.Delete("/", handler) // 方法: "OPTIONS" app.Options("/", handler) // 方法: "TRACE" app.Trace("/", handler) // 方法: "CONNECT" app.Connect("/", handler) // 方法: "HEAD" app.Head("/", handler) // 方法: "PATCH" app.Patch("/", handler) // 注册支持所有 HTTP 方法的路由 app.Any("/", handler) func handler(ctx iris.Context){ ctx.Writef("Hello from method: %s and path: %s\n", ctx.Method(), ctx.Path()) } ``` ### [离线路线](https://github.com/kataras/iris/wiki/Routing#offline-routes) 在 Iris 中有一种特别的方法。 它被称为 `None` 并且可以用它对外部隐藏一个路由, 但是你却可以通过 `Context.Exec` 方法从其他路由处理程序中调用它。每个 API 处理方法都会返回路由的 值。路由的 `IsOnline` 方法报告该路由的当前状态。你可以通过路由 `Route.Method` 字段的值,将路由的**状态**从**离线**改变**在线**。 当然,在服务时路由器的每次更改都需要一个`app.RefreshRouter()` 调用,该调用可以安全使用。下面看一个更完整的示例: ``` // 文件: main.go package main import ( "github.com/kataras/iris/v12" ) func main() { app := iris.New() none := app.None("/invisible/{username}", func(ctx iris.Context) { ctx.Writef("Hello %s with method: %s", ctx.Params().Get("username"), ctx.Method()) if from := ctx.Values().GetString("from"); from != "" { ctx.Writef("\nI see that you're coming from %s", from) } }) app.Get("/change", func(ctx iris.Context) { if none.IsOnline() { none.Method = iris.MethodNone } else { none.Method = iris.MethodGet } //刷新服务中重建的路由器,以便 // 收到新路线通知。 app.RefreshRouter() }) app.Get("/execute", func(ctx iris.Context) { if !none.IsOnline() { ctx.Values().Set("from", "/execute with offline access") ctx.Exec("NONE", "/invisible/iris") return } // 与导航到 "http://localhost:8080/invisible/iris" 相同 // 当 /change 被调用并且路由状态从 // "离线" 改变为 "在线" ctx.Values().Set("from", "/execute") // 值和 session 可以被共享, // 当调用 Exec 从一个"外部"的 Context。 // ctx.Exec("NONE", "/invisible/iris") // 或者在 "/change" 之后: ctx.Exec("GET", "/invisible/iris") }) app.Run(iris.Addr(":8080")) } ``` **如何运行** 1. `go run main.go` 2. 打开一个位于 `http://localhost:8080/invisible/iris` 的浏览器, 然后你会获得一个 `404 not found` 错误, 3. 但是 `http://localhost:8080/execute` 将能够执行该路由。 4. 现在,如果导航到 `http://localhost:8080/change` 并刷新 `/invisible/iris`选项卡 ,你将会看到它。 ## [路由分组](https://github.com/kataras/iris/wiki/Routing#grouping-routes) 被路径前缀分组的一组路由可以(可选)共享相同的中间件处理程序和模板布局。 一个组同时也可以有一个嵌套组。 `.Party` 用于对路由进行分组,开发人员可以声明无限数量的(嵌套)组。 示例代码: ``` app := iris.New() users := app.Party("/users", myAuthMiddlewareHandler) // http://localhost:8080/users/42/profile users.Get("/{id:uint64}/profile", userProfileHandler) // http://localhost:8080/users/messages/1 users.Get("/messages/{id:uint64}", userMessageHandler) ``` 也可以使用 `PartyFunc` 函数编写相同的方法,该方法接受子路由器(当前分组的子路由器)。 ```source-go app := iris.New() app.PartyFunc("/users", func(users iris.Party) { users.Use(myAuthMiddlewareHandler) // http://localhost:8080/users/42/profile users.Get("/{id:uint64}/profile", userProfileHandler) // http://localhost:8080/users/messages/1 users.Get("/messages/{id:uint64}", userMessageHandler) }) ``` ## [路径参数](https://github.com/kataras/iris/wiki/Routing#path-parameters) 和你以前见到的路由器不同,Iris 的路由器可以处理不同种类的路由而不会发生冲突。 仅仅匹配 GET "/" 路径。 ``` app.Get("/", indexHandler) ``` 匹配所有包含 `"/assets/**/*"` 前缀的 GET 请求, 它是一个 `ctx.Params().Get("asset")` 的通配符,等同于任何跟随在 `/assets/`之后的路径。 ``` app.Get("/assets/{asset:path}", assetsWildcardHandler) ``` 匹配所有以 `"/profile/"` 为前缀的 GET 请求,后跟随单个路径部分。 ``` app.Get("/profile/{username:string}", userHandler) ``` 1. 仅匹配 `"/profile/me"` GET 请求并且不与 `/profile/{username:string}` 请求或者任何root 通配符 `/{root:path}` 请求相冲突。 ``` app.Get("/profile/me", userHandler) ``` 匹配所有以 `/users/` 为前缀的GET请求,后跟一个等于或大于 1 的数字。 ``` app.Get("/user/{userid:int min(1)}", getUserHandler) ``` 匹配所有以 `/ users /`为前缀的 DELETE 请求,后跟一个等于或大于 1 的数字。 ``` app.Delete("/user/{userid:int min(1)}", deleteUserHandler) ``` 匹配除其他路由已处理的请求之外的所有 GET 请求。例如,在这个案例中,前面已经注册的路由; `/`, `/assets/{asset:path}`,`/profile/{username}`, `"/profile/me"`,`/user/{userid:int ...}`。它与其余路由(!)不冲突。 ``` app.Get("{root:path}", rootWildcardHandler) ``` 匹配以下所有 GET 请求: 1. /u/abcd 映射到 `:alphabetical` (如果 `:alphabetical` 已经被注册,则使用 `:string`) 2. /u/42 映射到 `:uint` (if `:uint` 已经被注册,则使用 `:int`) 3. /u/-1 映射到 `:int` (if `:int` 已经被注册,则使用 `:string`) 4. /u/abcd123 映射到 `:string` ``` app.Get("/u/{username:string}", func(ctx iris.Context) { ctx.Writef("username (string): %s", ctx.Params().Get("username")) }) app.Get("/u/{id:int}", func(ctx iris.Context) { ctx.Writef("id (int): %d", ctx.Params().GetIntDefault("id", 0)) }) app.Get("/u/{uid:uint}", func(ctx iris.Context) { ctx.Writef("uid (uint): %d", ctx.Params().GetUintDefault("uid", 0)) }) app.Get("/u/{firstname:alphabetical}", func(ctx iris.Context) { ctx.Writef("firstname (alphabetical): %s", ctx.Params().Get("firstname")) }) ``` 分别匹配 `/abctenchars.xml` 和 `/abcdtenchars` 的所有 GET 请求。 ``` app.Get("/{alias:string regexp(^[a-z0-9]{1,10}\\.xml$)}", PanoXML) app.Get("/{alias:string regexp(^[a-z0-9]{1,10}$)}", Tour) ``` 你可能想知道 `{id:uint64}` 或者 `:path` 或者 `min(1)` 是什么意思。 它们是(键入的)动态路径参数,可以在其上注册功能。通过阅读 [路由参数类型](https://github.com/kataras/iris/wiki/Routing-path-parameter-types) 了解更多信息。