安装

Iris是一个跨平台软件。
唯一的要求是Go编程语言,版本1.14及以上。

  1. $ mkdir myapp
  2. $ go mod init myapp
  3. $ go get github.com/kataras/iris/v12@master

导入它在您的代码:

  1. import "github.com/kataras/iris/v12"

疑问解答

如果您在安装期间出现网络错误,请确保您设置了一个有效的GOPROXY环境变量。

  1. go env -w GOPROXY=https://goproxy.cn,https://gocenter.io,https://goproxy.io,direct

快速开始


  1. # assume the following codes in main.go file
  2. $ cat main.go
  1. package main
  2. import "github.com/kataras/iris/v12"
  3. func main() {
  4. app := iris.New()
  5. booksAPI := app.Party("/books")
  6. {
  7. booksAPI.Use(iris.Compression)
  8. // GET: http://localhost:8080/books
  9. booksAPI.Get("/", list)
  10. // POST: http://localhost:8080/books
  11. booksAPI.Post("/", create)
  12. }
  13. app.Listen(":8080")
  14. }
  15. // Book example.
  16. type Book struct {
  17. Title string `json:"title"`
  18. }
  19. func list(ctx iris.Context) {
  20. books := []Book{
  21. {"Mastering Concurrency in Go"},
  22. {"Go Design Patterns"},
  23. {"Black Hat Go"},
  24. }
  25. ctx.JSON(books)
  26. // TIP: negotiate the response between server's prioritizes
  27. // and client's requirements, instead of ctx.JSON:
  28. // ctx.Negotiation().JSON().MsgPack().Protobuf()
  29. // ctx.Negotiate(books)
  30. }
  31. func create(ctx iris.Context) {
  32. var b Book
  33. err := ctx.ReadJSON(&b)
  34. // TIP: use ctx.ReadBody(&b) to bind
  35. // any type of incoming data instead.
  36. if err != nil {
  37. ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
  38. Title("Book creation failure").DetailErr(err))
  39. // TIP: use ctx.StopWithError(code, err) when only
  40. // plain text responses are expected on errors.
  41. return
  42. }
  43. println("Received Book: " + b.Title)
  44. ctx.StatusCode(iris.StatusCreated)
  45. }

MVC

  1. import "github.com/kataras/iris/v12/mvc"
  1. m := mvc.New(booksAPI)
  2. m.Handle(new(BookController))
  1. type BookController struct {
  2. /* dependencies */
  3. }
  4. // GET: http://localhost:8080/books
  5. func (c *BookController) Get() []Book {
  6. return []Book{
  7. {"Mastering Concurrency in Go"},
  8. {"Go Design Patterns"},
  9. {"Black Hat Go"},
  10. }
  11. }
  12. // POST: http://localhost:8080/books
  13. func (c *BookController) Post(b Book) int {
  14. println("Received Book: " + b.Title)
  15. return iris.StatusCreated
  16. }

运行你的iris Web服务:

  1. $ go run main.go
  2. > Now listening on: http://localhost:8080
  3. > Application started. Press CTRL+C to shut down.

Books 列表

  1. $ curl --header 'Accept-Encoding:gzip' http://localhost:8080/books
  2. [
  3. {
  4. "title": "Mastering Concurrency in Go"
  5. },
  6. {
  7. "title": "Go Design Patterns"
  8. },
  9. {
  10. "title": "Black Hat Go"
  11. }
  12. ]

创建一个新的Book

  1. $ curl -i -X POST \
  2. --header 'Content-Encoding:gzip' \
  3. --header 'Content-Type:application/json' \
  4. --data "{\"title\":\"Writing An Interpreter In Go\"}" \
  5. http://localhost:8080/books
  6. > HTTP/1.1 201 Created

错误相应

  1. $ curl -X POST --data "{\"title\" \"not valid one\"}" \
  2. http://localhost:8080/books
  3. > HTTP/1.1 400 Bad Request
  4. {
  5. "status": 400,
  6. "title": "Book creation failure"
  7. "detail": "invalid character '\"' after object key",
  8. }

基准测试

Iris使用了一个定制版本的muxie
See all benchmarks
动态参数的int 200000个请求,发送JSON请求主体和接收JSON响应。

Name Language Reqs/sec Latency Throughput Time To Complete
Iris Go 150430 826.05us 41.25MB 1.33s
Chi Go 146274 0.85ms 39.32MB 1.37s
Gin Go 141664 0.88ms 38.74MB 1.41s
Echo Go 138915 0.90ms 38.15MB 1.44s
Kestrel C# 136935 0.91ms 39.79MB 1.47s
Martini Go 128590 0.97ms 34.57MB 1.56s
Buffalo Go 58954 2.12ms 16.18MB 3.40s
Koa Javascript 50948 2.61ms 14.15MB 4.19s
Express Javascript 38451 3.24ms 13.77MB 5.21s

Api 例子

您可以在Iris示例库中找到许多准备运行的示例。

GET,POST,PUT,PATCH,DELETE and OPTIONS

  1. func main() {
  2. // Creates an iris application with default middleware:
  3. // Default with "debug" Logger Level.
  4. // Localization enabled on "./locales" directory
  5. // and HTML templates on "./views" or "./templates" directory.
  6. // It runs with the AccessLog on "./access.log",
  7. // Recovery (crash-free) and Request ID middleware already attached.
  8. app := iris.Default()
  9. app.Get("/someGet", getting)
  10. app.Post("/somePost", posting)
  11. app.Put("/somePut", putting)
  12. app.Delete("/someDelete", deleting)
  13. app.Patch("/somePatch", patching)
  14. app.Header("/someHead", head)
  15. app.Options("/someOptions", options)
  16. app.Listen(":8080")
  17. }

路径参数

  1. func main() {
  2. app := iris.Default()
  3. // This handler will match /user/john but will not match /user/ or /user
  4. app.Get("/user/{name}", func(ctx iris.Context) {
  5. name := ctx.Params().Get("name")
  6. ctx.Writef("Hello %s", name)
  7. })
  8. // However, this one will match /user/john/ and also /user/john/send
  9. // If no other routers match /user/john, it will redirect to /user/john/
  10. app.Get("/user/{name}/{action:path}", func(ctx iris.Context) {
  11. name := ctx.Params().Get("name")
  12. action := ctx.Params().Get("action")
  13. message := name + " is " + action
  14. ctx.WriteString(message)
  15. })
  16. // For each matched request Context will hold the route definition
  17. app.Post("/user/{name:string}/{action:path}", func(ctx iris.Context) {
  18. ctx.GetCurrentRoute().Tmpl().Src == "/user/{name:string}/{action:path}" // true
  19. })
  20. app.Listen(":8080")
  21. }

内置可用参数类型:

Param Type Go Type Validation Retrieve Helper
:string string anything (single path segment) Params().Get
:int int -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch Params().GetInt
:int8 int8 -128 to 127 Params().GetInt8
:int16 int16 -32768 to 32767 Params().GetInt16
:int32 int32 -2147483648 to 2147483647 Params().GetInt32
:int64 int64 -9223372036854775808 to 9223372036854775807 Params().GetInt64
:uint uint 0 to 18446744073709551615 (x64) or 0 to 4294967295 (x32), depends on the host arch Params().GetUint
:uint8 uint8 0 to 255 Params().GetUint8
:uint16 uint16 0 to 65535 Params().GetUint16
:uint32 uint32 0 to 4294967295 Params().GetUint32
:uint64 uint64 0 to 18446744073709551615 Params().GetUint64
:bool bool “1” or “t” or “T” or “TRUE” or “true” or “True” or “0” or “f” or “F” or “FALSE” or “false” or “False” Params().GetBool
:alphabetical string lowercase or uppercase letters Params().Get
:file string lowercase or uppercase letters, numbers, underscore (_), dash (-), point (.) and no spaces or other special characters that are not valid for filenames Params().Get
:path string anything, can be separated by slashes (path segments) but should be the last part of the route path Params().Get

More examples can be found at: _examples/routing.

查询字符串参数

  1. func main() {
  2. app := iris.Default()
  3. // Query string parameters are parsed using the existing underlying request object.
  4. // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe
  5. app.Get("/welcome", func(ctx iris.Context) {
  6. firstname := ctx.URLParamDefault("firstname", "Guest")
  7. lastname := ctx.URLParam("lastname") // shortcut for ctx.Request().URL.Query().Get("lastname")
  8. ctx.Writef("Hello %s %s", firstname, lastname)
  9. })
  10. app.Listen(":8080")
  11. }

表单 Multipart/Urlencoded

  1. func main() {
  2. app := iris.Default()
  3. app.Post("/form_post", func(ctx iris.Context) {
  4. message := ctx.PostValue("message")
  5. nick := ctx.PostValueDefault("nick", "anonymous")
  6. ctx.JSON(iris.Map{
  7. "status": "posted",
  8. "message": message,
  9. "nick": nick,
  10. })
  11. })
  12. app.Listen(":8080")
  13. }

另一个例子:查询+发布表单

  1. POST /post?id=1234&page=1 HTTP/1.1
  2. Content-Type: application/x-www-form-urlencoded
  3. name=kataras&message=this_is_great
  1. func main() {
  2. app := iris.Default()
  3. app.Post("/post", func(ctx iris.Context) {
  4. id, err := ctx.URLParamInt("id", 0)
  5. if err != nil {
  6. ctx.StopWithError(iris.StatusBadRequest, err)
  7. return
  8. }
  9. page := ctx.URLParamIntDefault("page", 0)
  10. name := ctx.PostValue("name")
  11. message := ctx.PostValue("message")
  12. ctx.Writef("id: %d; page: %d; name: %s; message: %s", id, page, name, message)
  13. })
  14. app.Listen(":8080")
  15. }
  1. id: 1234; page: 1; name: kataras; message: this_is_great

查询和发布表单参数

  1. POST /post?id=a&id=b&id=c&name=john&name=doe&name=kataras
  2. Content-Type: application/x-www-form-urlencoded
  1. func main() {
  2. app := iris.Default()
  3. app.Post("/post", func(ctx iris.Context) {
  4. ids := ctx.URLParamSlice("id")
  5. names, err := ctx.PostValues("name")
  6. if err != nil {
  7. ctx.StopWithError(iris.StatusBadRequest, err)
  8. return
  9. }
  10. ctx.Writef("ids: %v; names: %v", ids, names)
  11. })
  12. app.Listen(":8080")
  13. }
  1. ids: [a b c], names: [john doe kataras]

上传文件

单个文件

  1. const maxSize = 8 * iris.MB
  2. func main() {
  3. app := iris.Default()
  4. app.Post("/upload", func(ctx iris.Context) {
  5. // Set a lower memory limit for multipart forms (default is 32 MiB)
  6. ctx.SetMaxRequestBodySize(maxSize)
  7. // OR
  8. // app.Use(iris.LimitRequestBodySize(maxSize))
  9. // OR
  10. // OR iris.WithPostMaxMemory(maxSize)
  11. // single file
  12. file, _, err:= ctx.FormFile("file")
  13. if err != nil {
  14. ctx.StopWithError(iris.StatusBadRequest, err)
  15. return
  16. }
  17. // Upload the file to specific destination.
  18. dest := filepath.Join("./uploads", file.Filename)
  19. ctx.SaveFormFile(file, dest)
  20. ctx.Writef("File: %s uploaded!", file.Filename)
  21. })
  22. app.Listen(":8080")
  23. }

如何curl:

  1. curl -X POST http://localhost:8080/upload \
  2. -F "file=@/Users/kataras/test.zip" \
  3. -H "Content-Type: multipart/form-data"

多文件上传

查看示例代码细节

  1. func main() {
  2. app := iris.Default()
  3. app.Post("/upload", func(ctx iris.Context) {
  4. files, n, err := ctx.UploadFormFiles("./uploads")
  5. if err != nil {
  6. ctx.StopWithStatus(iris.StatusInternalServerError)
  7. return
  8. }
  9. ctx.Writef("%d files of %d total size uploaded!", len(files), n))
  10. })
  11. app.Listen(":8080", iris.WithPostMaxMemory(8 * iris.MB))
  12. }

如何curl:

  1. curl -X POST http://localhost:8080/upload \
  2. -F "upload[]=@/Users/kataras/test1.zip" \
  3. -F "upload[]=@/Users/kataras/test2.zip" \
  4. -H "Content-Type: multipart/form-data"

路由组

  1. func main() {
  2. app := iris.Default()
  3. // Simple group: v1
  4. v1 := app.Party("/v1")
  5. {
  6. v1.Post("/login", loginEndpoint)
  7. v1.Post("/submit", submitEndpoint)
  8. v1.Post("/read", readEndpoint)
  9. }
  10. // Simple group: v2
  11. v2 := app.Party("/v2")
  12. {
  13. v2.Post("/login", loginEndpoint)
  14. v2.Post("/submit", submitEndpoint)
  15. v2.Post("/read", readEndpoint)
  16. }
  17. app.Listen(":8080")
  18. }

默认情况下没有中间件

使用

  1. app := iris.New()

代替

  1. // Default with "debug" Logger Level.
  2. // Localization enabled on "./locales" directory
  3. // and HTML templates on "./views" or "./templates" directory.
  4. // It runs with the AccessLog on "./access.log",
  5. // Recovery and Request ID middleware already attached.
  6. app := iris.Default()

使用中间件

  1. package main
  2. import (
  3. "github.com/kataras/iris/v12"
  4. "github.com/kataras/iris/v12/middleware/logger"
  5. "github.com/kataras/iris/v12/middleware/recover"
  6. )
  7. func main() {
  8. // Creates an iris application without any middleware by default
  9. app := iris.New()
  10. // Global middleware using `UseRouter`.
  11. //
  12. // Recovery middleware recovers from any panics and writes a 500 if there was one.
  13. app.UseRouter(recover.New())
  14. // Logger middleware by-default will write the logs using app.Logger().Infof.
  15. app.UseRouter(logger.New())
  16. // Per route middleware, you can add as many as you desire.
  17. app.Get("/benchmark", MyBenchLogger(), benchEndpoint)
  18. // Authorization group
  19. // authorized := app.Party("/", AuthRequired())
  20. // exactly the same as:
  21. authorized := app.Party("/")
  22. // per group middleware! in this case we use the custom created
  23. // AuthRequired() middleware just in the "authorized" group.
  24. authorized.Use(AuthRequired())
  25. {
  26. authorized.Post("/login", loginEndpoint)
  27. authorized.Post("/submit", submitEndpoint)
  28. authorized.Post("/read", readEndpoint)
  29. // nested group
  30. testing := authorized.Party("testing")
  31. testing.Get("/analytics", analyticsEndpoint)
  32. }
  33. // Listen and serve on 0.0.0.0:8080
  34. app.Listen(":8080")
  35. }

如何写日志文件

  1. func main() {
  2. app := iris.Default()
  3. // Logging to a file.
  4. // Colors are automatically disabled when writing to a file.
  5. f, _ := os.Create("iris.log")
  6. app.Logger().SetOutput(f)
  7. // Use the following code if you need to write the logs
  8. // to file and console at the same time.
  9. // app.Logger().AddOutput(os.Stdout)
  10. app.Get("/ping", func(ctx iris.Context) {
  11. ctx.WriteString("pong")
  12. })
  13. app.Listen(":8080")
  14. }

自定义请求日志

搜索access.log功能代替?详细的例子可以在这里找到。

  1. // LogFunc field.
  2. func customLogFunc(endTime time.Time,
  3. latency time.Duration,
  4. status, ip, method, path string,
  5. message, headerMessage interface{}) {
  6. // [...]
  7. }
  1. // LogFuncCtx field.
  2. func customLogFuncWithContext(ctx iris.Context, latency time.Duration) {
  3. // [...]
  4. }
  1. import "github.com/kataras/iris/v12/middleware/logger"
  2. func main() {
  3. app := iris.New()
  4. reqLogger := logger.New(logger.Config{
  5. Status: true,
  6. IP: true,
  7. Method: true,
  8. Path: true,
  9. PathAfterHandler: false,
  10. Query: false,
  11. TraceRoute: true,
  12. Columns: false,
  13. LogFunc: customLogFunc,
  14. LogFuncCtx: nil,
  15. Skippers: nil,
  16. })
  17. app.UseRouter(reqLogger)
  18. app.Get("/ping", func(ctx iris.Context) {
  19. ctx.WriteString("pong")
  20. })
  21. app.Listen(":8080")
  22. }

控制日志输入颜色

默认情况下,控制台上的日志输出应该根据检测到的TTY着色。
自定义级别标题,文本,颜色和样式。
Import golog and pio:

  1. import (
  2. "github.com/kataras/golog"
  3. "github.com/kataras/pio"
  4. // [...]
  5. )

自定义一个级别,例如DebugLevel:

  1. level := golog.Levels[golog.DebugLevel]

你可以完全控制他的文本,标题和风格:

  1. // The Name of the Level
  2. // that named (lowercased) will be used
  3. // to convert a string level on `SetLevel`
  4. // to the correct Level type.
  5. Name string
  6. // AlternativeNames are the names that can be referred to this specific log level.
  7. // i.e Name = "warn"
  8. // AlternativeNames = []string{"warning"}, it's an optional field,
  9. // therefore we keep Name as a simple string and created this new field.
  10. AlternativeNames []string
  11. // Tha Title is the prefix of the log level.
  12. // See `ColorCode` and `Style` too.
  13. // Both `ColorCode` and `Style` should be respected across writers.
  14. Title string
  15. // ColorCode a color for the `Title`.
  16. ColorCode int
  17. // Style one or more rich options for the `Title`.
  18. Style []pio.RichOption

示例代码:

  1. level := golog.Levels[golog.DebugLevel]
  2. level.Name = "debug" // default
  3. level.Title = "[DBUG]" // default
  4. level.ColorCode = pio.Yellow // default

更改格式化输出:

  1. app.Logger().SetFormat("json", " ")

注册自定义格式化程序:

  1. app.Logger().RegisterFormatter(new(myFormatter))

golog.Formatter interface 看起来像这样:

  1. // Formatter is responsible to print a log to the logger's writer.
  2. type Formatter interface {
  3. // The name of the formatter.
  4. String() string
  5. // Set any options and return a clone,
  6. // generic. See `Logger.SetFormat`.
  7. Options(opts ...interface{}) Formatter
  8. // Writes the "log" to "dest" logger.
  9. Format(dest io.Writer, log *Log) bool
  10. }

改变输出和格式每层:

  1. app.Logger().SetLevelOutput("error", os.Stderr)
  2. app.Logger().SetLevelFormat("json")

Model绑定和验证

要将请求主体绑定到类型中,请使用模型绑定。我们目前支持JSON绑定,JSONProtobuf, Protobuf, MsgPack, XML, YAML and standard form values (foo=bar&boo=baz).

  1. ReadJSON(outPtr interface{}) error
  2. ReadJSONProtobuf(ptr proto.Message, opts ...ProtoUnmarshalOptions) error
  3. ReadProtobuf(ptr proto.Message) error
  4. ReadMsgPack(ptr interface{}) error
  5. ReadXML(outPtr interface{}) error
  6. ReadYAML(outPtr interface{}) error
  7. ReadForm(formObject interface{}) error
  8. ReadQuery(ptr interface{}) error

在使用读取体时,Iris尝试根据内容类型标题推断绑定器。如果确定要绑定的是什么,可以使用特定的ReadXXX方法,例如ReadJSON或ReadProtobuf和e.t.c。

  1. ReadBody(ptr interface{}) error

明智的是,Iris不提供内置数据验证。但是,它允许你附加一个验证器,自动调用方法,如ReadJSON, ReadXML…在这个示例中,我们将学习如何使用go-playground/validator/v10进行请求体验证。

注意,您需要在所有想要绑定的字段上设置相应的绑定标记。例如,当从JSON绑定时,设置JSON:“fieldname”。

您还可以指定所需的特定字段。如果一个字段用binding:”required”修饰,并且在绑定时有一个空值,那么将返回一个错误。

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/kataras/iris/v12"
  5. "github.com/go-playground/validator/v10"
  6. )
  7. func main() {
  8. app := iris.New()
  9. app.Validator = validator.New()
  10. userRouter := app.Party("/user")
  11. {
  12. userRouter.Get("/validation-errors", resolveErrorsDocumentation)
  13. userRouter.Post("/", postUser)
  14. }
  15. app.Listen(":8080")
  16. }
  17. // User contains user information.
  18. type User struct {
  19. FirstName string `json:"fname" validate:"required"`
  20. LastName string `json:"lname" validate:"required"`
  21. Age uint8 `json:"age" validate:"gte=0,lte=130"`
  22. Email string `json:"email" validate:"required,email"`
  23. FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"`
  24. Addresses []*Address `json:"addresses" validate:"required,dive,required"`
  25. }
  26. // Address houses a users address information.
  27. type Address struct {
  28. Street string `json:"street" validate:"required"`
  29. City string `json:"city" validate:"required"`
  30. Planet string `json:"planet" validate:"required"`
  31. Phone string `json:"phone" validate:"required"`
  32. }
  33. type validationError struct {
  34. ActualTag string `json:"tag"`
  35. Namespace string `json:"namespace"`
  36. Kind string `json:"kind"`
  37. Type string `json:"type"`
  38. Value string `json:"value"`
  39. Param string `json:"param"`
  40. }
  41. func wrapValidationErrors(errs validator.ValidationErrors) []validationError {
  42. validationErrors := make([]validationError, 0, len(errs))
  43. for _, validationErr := range errs {
  44. validationErrors = append(validationErrors, validationError{
  45. ActualTag: validationErr.ActualTag(),
  46. Namespace: validationErr.Namespace(),
  47. Kind: validationErr.Kind().String(),
  48. Type: validationErr.Type().String(),
  49. Value: fmt.Sprintf("%v", validationErr.Value()),
  50. Param: validationErr.Param(),
  51. })
  52. }
  53. return validationErrors
  54. }
  55. func postUser(ctx iris.Context) {
  56. var user User
  57. err := ctx.ReadJSON(&user)
  58. if err != nil {
  59. // Handle the error, below you will find the right way to do that...
  60. if errs, ok := err.(validator.ValidationErrors); ok {
  61. // Wrap the errors with JSON format, the underline library returns the errors as interface.
  62. validationErrors := wrapValidationErrors(errs)
  63. // Fire an application/json+problem response and stop the handlers chain.
  64. ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
  65. Title("Validation error").
  66. Detail("One or more fields failed to be validated").
  67. Type("/user/validation-errors").
  68. Key("errors", validationErrors))
  69. return
  70. }
  71. // It's probably an internal JSON error, let's dont give more info here.
  72. ctx.StopWithStatus(iris.StatusInternalServerError)
  73. return
  74. }
  75. ctx.JSON(iris.Map{"message": "OK"})
  76. }
  77. func resolveErrorsDocumentation(ctx iris.Context) {
  78. ctx.WriteString("A page that should document to web developers or users of the API on how to resolve the validation errors")
  79. }

简单请求

  1. {
  2. "fname": "",
  3. "lname": "",
  4. "age": 45,
  5. "email": "mail@example.com",
  6. "favColor": "#000",
  7. "addresses": [{
  8. "street": "Eavesdown Docks",
  9. "planet": "Persphone",
  10. "phone": "none",
  11. "city": "Unknown"
  12. }]
  13. }

简单响应

  1. {
  2. "title": "Validation error",
  3. "detail": "One or more fields failed to be validated",
  4. "type": "http://localhost:8080/user/validation-errors",
  5. "status": 400,
  6. "fields": [
  7. {
  8. "tag": "required",
  9. "namespace": "User.FirstName",
  10. "kind": "string",
  11. "type": "string",
  12. "value": "",
  13. "param": ""
  14. },
  15. {
  16. "tag": "required",
  17. "namespace": "User.LastName",
  18. "kind": "string",
  19. "type": "string",
  20. "value": "",
  21. "param": ""
  22. }
  23. ]
  24. }

了解更多关于模型验证的信息:https://github.com/go-playground/validator/blob/master/_examples

绑定查询字符串

ReadQuery方法只绑定查询参数而不是post数据,使用ReadForm来绑定post数据。

  1. package main
  2. import "github.com/kataras/iris/v12"
  3. type Person struct {
  4. Name string `url:"name,required"`
  5. Address string `url:"address"`
  6. }
  7. func main() {
  8. app := iris.Default()
  9. app.Any("/", index)
  10. app.Listen(":8080")
  11. }
  12. func index(ctx iris.Context) {
  13. var person Person
  14. if err := ctx.ReadQuery(&person); err!=nil {
  15. ctx.StopWithError(iris.StatusBadRequest, err)
  16. return
  17. }
  18. ctx.Application().Logger().Infof("Person: %#+v", person)
  19. ctx.WriteString("Success")
  20. }

绑定任何

根据客户端发送数据的内容类型,如JSON、XML、YAML、MessagePack、Protobuf、Form和URL查询,将请求体绑定到“ptr”。

  1. package main
  2. import (
  3. "time"
  4. "github.com/kataras/iris/v12"
  5. )
  6. type Person struct {
  7. Name string `form:"name" json:"name" url:"name" msgpack:"name"`
  8. Address string `form:"address" json:"address" url:"address" msgpack:"address"`
  9. Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1" json:"birthday" url:"birthday" msgpack:"birthday"`
  10. CreateTime time.Time `form:"createTime" time_format:"unixNano" json:"create_time" url:"create_time" msgpack:"createTime"`
  11. UnixTime time.Time `form:"unixTime" time_format:"unix" json:"unix_time" url:"unix_time" msgpack:"unixTime"`
  12. }
  13. func main() {
  14. app := iris.Default()
  15. app.Any("/", index)
  16. app.Listen(":8080")
  17. }
  18. func index(ctx iris.Context) {
  19. var person Person
  20. if err := ctx.ReadBody(&person); err!=nil {
  21. ctx.StopWithError(iris.StatusBadRequest, err)
  22. return
  23. }
  24. ctx.Application().Logger().Infof("Person: %#+v", person)
  25. ctx.WriteString("Success")
  26. }

测试:

  1. $ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"

绑定url路径参数

  1. package main
  2. import "github.com/kataras/iris/v12"
  3. type myParams struct {
  4. Name string `param:"name"`
  5. Age int `param:"age"`
  6. Tail []string `param:"tail"`
  7. }
  8. // All parameters are required, as we already know,
  9. // the router will fire 404 if name or int or tail are missing.
  10. func main() {
  11. app := iris.Default()
  12. app.Get("/{name}/{age:int}/{tail:path}", func(ctx iris.Context) {
  13. var p myParams
  14. if err := ctx.ReadParams(&p); err != nil {
  15. ctx.StopWithError(iris.StatusInternalServerError, err)
  16. return
  17. }
  18. ctx.Writef("myParams: %#v", p)
  19. })
  20. app.Listen(":8088")
  21. }

请求

  1. $ curl -v http://localhost:8080/kataras/27/iris/web/framework

header头绑定

  1. package main
  2. import "github.com/kataras/iris/v12"
  3. type myHeaders struct {
  4. RequestID string `header:"X-Request-Id,required"`
  5. Authentication string `header:"Authentication,required"`
  6. }
  7. func main() {
  8. app := iris.Default()
  9. r.GET("/", func(ctx iris.Context) {
  10. var hs myHeaders
  11. if err := ctx.ReadHeaders(&hs); err != nil {
  12. ctx.StopWithError(iris.StatusInternalServerError, err)
  13. return
  14. }
  15. ctx.JSON(hs)
  16. })
  17. app.Listen(":8080")
  18. }

请求

  1. curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \
  2. http://localhost:8080

响应

  1. {
  2. "RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73",
  3. "Authentication": "Bearer my-token"
  4. }

绑定HTML 复选框

  1. package main
  2. import "github.com/kataras/iris/v12"
  3. func main() {
  4. app := iris.New()
  5. app.RegisterView(iris.HTML("./templates", ".html"))
  6. app.Get("/", showForm)
  7. app.Post("/", handleForm)
  8. app.Listen(":8080")
  9. }
  10. func showForm(ctx iris.Context) {
  11. ctx.View("form.html")
  12. }
  13. type formExample struct {
  14. Colors []string `form:"colors[]"` // or just "colors".
  15. }
  16. func handleForm(ctx iris.Context) {
  17. var form formExample
  18. err := ctx.ReadForm(&form)
  19. if err != nil {
  20. ctx.StopWithError(iris.StatusBadRequest, err)
  21. return
  22. }
  23. ctx.JSON(iris.Map{"Colors": form.Colors})
  24. }

templates/form.html

  1. <form action="/" method="POST">
  2. <p>Check one or more colors</p>
  3. <label for="red">Red</label>
  4. <!-- name can be "colors" too -->
  5. <input type="checkbox" name="colors[]" value="red" id="red">
  6. <label for="green">Green</label>
  7. <input type="checkbox" name="colors[]" value="green" id="green">
  8. <label for="blue">Blue</label>
  9. <input type="checkbox" name="colors[]" value="blue" id="blue">
  10. <input type="submit">
  11. </form>

响应

  1. {
  2. "Colors": [
  3. "red",
  4. "green",
  5. "blue"
  6. ]
  7. }

JSON,JSONP,XML,Markdown,YAML and MsgPack rendering

示例细节在这里可以找到

  1. func main() {
  2. app := iris.New()
  3. // iris.Map is an alias of map[string]interface{}
  4. app.Get("/json", func(ctx iris.Context) {
  5. ctx.JSON(iris.Map{"message": "hello", "status": iris.StatusOK})
  6. })
  7. // Use Secure field to prevent json hijacking.
  8. // It prepends `"while(1),"` to the body when the data is array.
  9. app.Get("/json_secure", func(ctx iris.Context) {
  10. response := []string{"val1", "val2", "val3"}
  11. options := iris.JSON{Indent: "", Secure: true}
  12. ctx.JSON(response, options)
  13. // Will output: while(1);["val1","val2","val3"]
  14. })
  15. // Use ASCII field to generate ASCII-only JSON
  16. // with escaped non-ASCII characters.
  17. app.Get("/json_ascii", func(ctx iris.Context) {
  18. response := iris.Map{"lang": "GO-虹膜", "tag": "<br>"}
  19. options := iris.JSON{Indent: " ", ASCII: true}
  20. ctx.JSON(response, options)
  21. /* Will output:
  22. {
  23. "lang": "GO-\u8679\u819c",
  24. "tag": "\u003cbr\u003e"
  25. }
  26. */
  27. })
  28. // Normally, JSON replaces special HTML characters with their unicode entities.
  29. // If you want to encode such characters literally,
  30. // you SHOULD set the UnescapeHTML field to true.
  31. app.Get("/json_raw", func(ctx iris.Context) {
  32. options := iris.JSON{UnescapeHTML: true}
  33. ctx.JSON(iris.Map{
  34. "html": "<b>Hello, world!</b>",
  35. }, options)
  36. // Will output: {"html":"<b>Hello, world!</b>"}
  37. })
  38. app.Get("/json_struct", func(ctx iris.Context) {
  39. // You also can use a struct.
  40. var msg struct {
  41. Name string `json:"user"`
  42. Message string
  43. Number int
  44. }
  45. msg.Name = "Mariah"
  46. msg.Message = "hello"
  47. msg.Number = 42
  48. // Note that msg.Name becomes "user" in the JSON.
  49. // Will output: {"user": "Mariah", "Message": "hello", "Number": 42}
  50. ctx.JSON(msg)
  51. })
  52. app.Get("/jsonp", func(ctx iris.Context) {
  53. ctx.JSONP(iris.Map{"hello": "jsonp"}, iris.JSONP{Callback: "callbackName"})
  54. })
  55. app.Get("/xml", func(ctx iris.Context) {
  56. ctx.XML(iris.Map{"message": "hello", "status": iris.StatusOK})
  57. })
  58. app.Get("/markdown", func(ctx iris.Context) {
  59. ctx.Markdown([]byte("# Hello Dynamic Markdown -- iris"))
  60. })
  61. app.Get("/yaml", func(ctx iris.Context) {
  62. ctx.YAML(iris.Map{"message": "hello", "status": iris.StatusOK})
  63. })
  64. app.Get("/msgpack", func(ctx iris.Context) {
  65. u := User{
  66. Firstname: "John",
  67. Lastname: "Doe",
  68. City: "Neither FBI knows!!!",
  69. Age: 25,
  70. }
  71. ctx.MsgPack(u)
  72. })
  73. // Render using jsoniter instead of the encoding/json:
  74. app.Listen(":8080", iris.WithOptimizations)
  75. }

Protobuf

Iris支持原生原生的protobuf和protobuf对JSON的编码和解码。

  1. package main
  2. import (
  3. "app/protos"
  4. "github.com/kataras/iris/v12"
  5. )
  6. func main() {
  7. app := iris.New()
  8. app.Get("/", send)
  9. app.Get("/json", sendAsJSON)
  10. app.Post("/read", read)
  11. app.Post("/read_json", readFromJSON)
  12. app.Listen(":8080")
  13. }
  14. func send(ctx iris.Context) {
  15. response := &protos.HelloReply{Message: "Hello, World!"}
  16. ctx.Protobuf(response)
  17. }
  18. func sendAsJSON(ctx iris.Context) {
  19. response := &protos.HelloReply{Message: "Hello, World!"}
  20. options := iris.JSON{
  21. Proto: iris.ProtoMarshalOptions{
  22. AllowPartial: true,
  23. Multiline: true,
  24. Indent: " ",
  25. },
  26. }
  27. ctx.JSON(response, options)
  28. }
  29. func read(ctx iris.Context) {
  30. var request protos.HelloRequest
  31. err := ctx.ReadProtobuf(&request)
  32. if err != nil {
  33. ctx.StopWithError(iris.StatusBadRequest, err)
  34. return
  35. }
  36. ctx.Writef("HelloRequest.Name = %s", request.Name)
  37. }
  38. func readFromJSON(ctx iris.Context) {
  39. var request protos.HelloRequest
  40. err := ctx.ReadJSONProtobuf(&request)
  41. if err != nil {
  42. ctx.StopWithError(iris.StatusBadRequest, err)
  43. return
  44. }
  45. ctx.Writef("HelloRequest.Name = %s", request.Name)
  46. }

使用静态文件

  1. func main() {
  2. app := iris.New()
  3. app.Favicon("./resources/favicon.ico")
  4. app.HandleDir("/assets", iris.Dir("./assets"))
  5. app.Listen(":8080")
  6. }

HandleDir方法接受第三个可选参数DirOptions:

  1. type DirOptions struct {
  2. // Defaults to "/index.html", if request path is ending with **/*/$IndexName
  3. // then it redirects to **/*(/) which another handler is handling it,
  4. // that another handler, called index handler, is auto-registered by the framework
  5. // if end developer does not managed to handle it by hand.
  6. IndexName string
  7. // PushTargets filenames (map's value) to
  8. // be served without additional client's requests (HTTP/2 Push)
  9. // when a specific request path (map's key WITHOUT prefix)
  10. // is requested and it's not a directory (it's an `IndexFile`).
  11. //
  12. // Example:
  13. // "/": {
  14. // "favicon.ico",
  15. // "js/main.js",
  16. // "css/main.css",
  17. // }
  18. PushTargets map[string][]string
  19. // PushTargetsRegexp like `PushTargets` but accepts regexp which
  20. // is compared against all files under a directory (recursively).
  21. // The `IndexName` should be set.
  22. //
  23. // Example:
  24. // "/": regexp.MustCompile("((.*).js|(.*).css|(.*).ico)$")
  25. // See `iris.MatchCommonAssets` too.
  26. PushTargetsRegexp map[string]*regexp.Regexp
  27. // Cache to enable in-memory cache and pre-compress files.
  28. Cache DirCacheOptions
  29. // When files should served under compression.
  30. Compress bool
  31. // List the files inside the current requested directory if `IndexName` not found.
  32. ShowList bool
  33. // If `ShowList` is true then this function will be used instead
  34. // of the default one to show the list of files of a current requested directory(dir).
  35. // See `DirListRich` package-level function too.
  36. DirList DirListFunc
  37. // Files downloaded and saved locally.
  38. Attachments Attachments
  39. // Optional validator that loops through each requested resource.
  40. AssetValidator func(ctx *context.Context, name string) bool
  41. }

了解更多关于文件服务器的信息。

上下文服务数据

  1. SendFile(filename string, destinationName string) error
  2. SendFileWithRate(src, destName string, limit float64, burst int) error

使用

强制发送文件到客户端:

  1. func handler(ctx iris.Context) {
  2. src := "./files/first.zip"
  3. ctx.SendFile(src, "client.zip")
  4. }

限制下载速度~50Kb/s,一次100KB的下载:

  1. func handler(ctx iris.Context) {
  2. src := "./files/big.zip"
  3. // optionally, keep it empty to resolve the filename based on the "src".
  4. dest := ""
  5. limit := 50.0 * iris.KB
  6. burst := 100 * iris.KB
  7. ctx.SendFileWithRate(src, dest, limit, burst)
  8. }
  1. ServeContent(content io.ReadSeeker, filename string, modtime time.Time)
  2. ServeContentWithRate(content io.ReadSeeker, filename string, modtime time.Time, limit float64, burst int)
  3. ServeFile(filename string) error
  4. ServeFileWithRate(filename string, limit float64, burst int) error

使用

  1. func handler(ctx iris.Context) {
  2. ctx.ServeFile("./public/main.js")
  3. }

模式渲染

Iris支持8个开箱即用的模板引擎,开发人员仍然可以使用任何外部的golang模板引擎,因为Context.ResponseWriter()是一个io.Writer。

所有的模板引擎都共享一个通用的API,例如使用嵌入资产的解析,布局和特定于团队的布局,模板函数,部分渲染等等。

# Name Parser
1 HTML html/template
2 Blocks kataras/blocks
3 Django flosch/pongo2
4 Pug Joker/jade
5 Handlebars aymerick/raymond
6 Amber eknkc/amber
7 Jet CloudyKit/jet
8 Ace yosssi/ace

List of Examples
List of Benchmarks
视图引擎可以为每一方注册。要注册一个视图引擎,可以使用Application/Party.RegisterView(ViewEngine)方法,如下所示。

从”./view”目录加载所有扩展名是”.html”,并使用标准的html/模板包解析它们。

  1. // [app := iris.New...]
  2. tmpl := iris.HTML("./views", ".html")
  3. app.RegisterView(tmpl)

使用Context.View呈现或执行视图。视图方法在主路由的处理程序内。

  1. ctx.View("hi.html")

要通过中间件或主处理程序在视图中使用键-值模式绑定Go值,请使用上下文。在Context.View之前的ViewData方法。一个视图。

绑定值为”Hello world”的变量。

  1. ctx.ViewData("message", "Hello world!")

根绑定:

  1. ctx.View("user-page.html", User{})
  2. // root binding as {{.Name}}

要添加模板函数,请使用首选视图引擎的AddFunc方法。

  1. // func name, input arguments, render value
  2. tmpl.AddFunc("greet", func(s string) string {
  3. return "Greetings " + s + "!"
  4. })

要在每个请求上重新加载,请调用视图引擎的reload方法。

  1. tmpl.Reload(true)

要使用嵌入式模板而不依赖于本地文件系统,请使用go-bindata外部工具并将其AssetFile()生成的函数传递给首选视图引擎的第一个输入参数。

  1. tmpl := iris.HTML(AssetFile(), ".html")

代码示例:

  1. // file: main.go
  2. package main
  3. import "github.com/kataras/iris/v12"
  4. func main() {
  5. app := iris.New()
  6. // Parse all templates from the "./views" folder
  7. // where extension is ".html" and parse them
  8. // using the standard `html/template` package.
  9. tmpl := iris.HTML("./views", ".html")
  10. // Set custom delimeters.
  11. tmpl.Delims("{{", "}}")
  12. // Enable re-build on local template files changes.
  13. tmpl.Reload(true)
  14. // Default template funcs are:
  15. //
  16. // - {{ urlpath "myNamedRoute" "pathParameter_ifNeeded" }}
  17. // - {{ render "header.html" }}
  18. // and partial relative path to current page:
  19. // - {{ render_r "header.html" }}
  20. // - {{ yield }}
  21. // - {{ current }}
  22. // Register a custom template func:
  23. tmpl.AddFunc("greet", func(s string) string {
  24. return "Greetings " + s + "!"
  25. })
  26. // Register the view engine to the views,
  27. // this will load the templates.
  28. app.RegisterView(tmpl)
  29. // Method: GET
  30. // Resource: http://localhost:8080
  31. app.Get("/", func(ctx iris.Context) {
  32. // Bind: {{.message}} with "Hello world!"
  33. ctx.ViewData("message", "Hello world!")
  34. // Render template file: ./views/hi.html
  35. ctx.View("hi.html")
  36. })
  37. app.Listen(":8080")
  38. }
  1. <!-- file: ./views/hi.html -->
  2. <html>
  3. <head>
  4. <title>Hi Page</title>
  5. </head>
  6. <body>
  7. <h1>{{.message}}</h1>
  8. <strong>{{greet "to you"}}</strong>
  9. </body>
  10. </html>

访问http://localhost:8080

已经渲染的效果看起来像这样:

  1. <html>
  2. <head>
  3. <title>Hi Page</title>
  4. </head>
  5. <body>
  6. <h1>Hello world!</h1>
  7. <strong>Greetings to you!</strong>
  8. </body>
  9. </html>

多个模板文件

Iris允许每个应用程序无限制地注册视图引擎。除此之外,您还可以为每一方或通过中间件注册一个视图引擎!

  1. // Register a view engine per group of routes.
  2. adminGroup := app.Party("/admin")
  3. adminGroup.RegisterView(iris.Blocks("./views/admin", ".html"))

通过中间件

  1. func middleware(views iris.ViewEngine) iris.Handler {
  2. return func(ctx iris.Context) {
  3. ctx.ViewEngine(views)
  4. ctx.Next()
  5. }
  6. }

使用

  1. // Register a view engine on-fly for the current chain of handlers.
  2. views := iris.Blocks("./views/on-fly", ".html")
  3. views.Load()
  4. app.Get("/", setViews(views), onFly)

重定向

发出HTTP重定向很容易。支持内部和外部位置。我们说的位置是指路径,子域,域等等。

处理器

  1. app.Get("/", func(ctx iris.Context) {
  2. ctx.Redirect("https://golang.org/dl", iris.StatusMovedPermanently)
  3. })

从POST发出HTTP重定向。

  1. app.Post("/", func(ctx iris.Context) {
  2. ctx.Redirect("/login", iris.StatusFound)
  3. })

从处理程序发出本地路由器重定向,使用应用程序。ServeHTTPC或Exec(),如下所示。

  1. app.Get("/test", func(ctx iris.Context) {
  2. r := ctx.Request()
  3. r.URL.Path = "/test2"
  4. ctx.Application().ServeHTTPC(ctx)
  5. // OR
  6. // ctx.Exec("GET", "/test2")
  7. })
  8. app.Get("/test2", func(ctx iris.Context) {
  9. ctx.JSON(iris.Map{"hello": "world"})
  10. })

全局

使用我们都喜欢的语法。

  1. import "github.com/kataras/iris/v12/middleware/rewrite"
  1. func main() {
  2. app := iris.New()
  3. // [...routes]
  4. redirects := rewrite.Load("redirects.yml")
  5. app.WrapRouter(redirects)
  6. app.Listen(":80")
  7. }

redirect.yml 示例:

  1. RedirectMatch:
  2. # Redirects /seo/* to /*
  3. - 301 /seo/(.*) /$1
  4. # Redirects /docs/v12* to /docs
  5. - 301 /docs/v12(.*) /docs
  6. # Redirects /old(.*) to /
  7. - 301 /old(.*) /
  8. # Redirects http or https://test.* to http or https://newtest.*
  9. - 301 ^(http|https)://test.(.*) $1://newtest.$2
  10. # Handles /*.json or .xml as *?format=json or xml,
  11. # without redirect. See /users route.
  12. # When Code is 0 then it does not redirect the request,
  13. # instead it changes the request URL
  14. # and leaves a route handle the request.
  15. - 0 /(.*).(json|xml) /$1?format=$2
  16. # Redirects root domain to www.
  17. # Creation of a www subdomain inside the Application is unnecessary,
  18. # all requests are handled by the root Application itself.
  19. PrimarySubdomain: www

例子链接:rewrite middleware example.

自定义中间件

  1. func Logger() iris.Handler {
  2. return func(ctx iris.Context) {
  3. t := time.Now()
  4. // Set a shared variable between handlers
  5. ctx.Values().Set("framework", "iris")
  6. // before request
  7. ctx.Next()
  8. // after request
  9. latency := time.Since(t)
  10. log.Print(latency)
  11. // access the status we are sending
  12. status := ctx.GetStatusCode()
  13. log.Println(status)
  14. }
  15. }
  16. func main() {
  17. app := iris.New()
  18. app.Use(Logger())
  19. app.Get("/test", func(ctx iris.Context) {
  20. // retrieve a value set by the middleware.
  21. framework := ctx.Values().GetString("framework")
  22. // it would print: "iris"
  23. log.Println(framework)
  24. })
  25. app.Listen(":8080")
  26. }

使用基本身份信息验证

导入basicauth 中间件

  1. import "github.com/kataras/iris/v12/middleware/basicauth"
  1. func main() {
  2. app := iris.New()
  3. // Group using basicauth middleware.
  4. authConfig := basicauth.Config{
  5. Users: map[string]string{
  6. "admin": "admin_password",
  7. "user" : "user_password",
  8. },
  9. Realm: "Authorization Required",
  10. Expires: time.Duration(30) * time.Minute,
  11. }
  12. authorized := app.Party("/admin", basicauth.New(authConfig))
  13. // /admin/secrets endpoint
  14. // hit "localhost:8080/admin/secrets
  15. authorized.Get("/secrets", func(ctx iris.Context) {
  16. // get user, it was set by the BasicAuth middleware
  17. username, password, _ := ctx.Request().BasicAuth()
  18. ctx.Writef("Hello, %s!", username)
  19. // [...]
  20. })
  21. app.Listen(":8080")
  22. }

如果您想注册一个没有匹配路由和错误的中间件,您应该使用UseRouter方法。例如,如果你也想保护/admin 404s,那么这样做:

  1. authorized.UseRouter(basicauth.New(authConfig))

更多例子:_examples/auth.

中间件中的Goroutines

当在中间件或处理程序中启动新的Goroutines时,您不应该在其中使用原始上下文,您必须使用只读副本。

  1. func main() {
  2. app := iris.Default()
  3. app.Get("/long_async", func(ctx iris.Context) {
  4. // create a clone to be used inside the goroutine
  5. ctxCopy := ctx.Clone()
  6. go func() {
  7. // simulate a long task with time.Sleep(). 5 seconds
  8. time.Sleep(5 * time.Second)
  9. // note that you are using the copied context "ctxCopy", IMPORTANT
  10. log.Printf("Done! in path: %s", ctxCopy.Path())
  11. }()
  12. })
  13. app.Get("/long_sync", func(ctx iris.Context) {
  14. // simulate a long task with time.Sleep(). 5 seconds
  15. time.Sleep(5 * time.Second)
  16. // since we are NOT using a goroutine, we do not have to copy the context
  17. log.Printf("Done! in path: %s", ctx.Path())
  18. })
  19. app.Listen(":8080")
  20. }

自定义HTTP配置

_examples/http-server文件夹中可以找到超过12个关于http服务器配置的示例。
直接使用http.ListenAndServe(),如下所示:

  1. func main() {
  2. app := iris.New()
  3. // [...routes]
  4. if err := app.Build(); err!=nil{
  5. panic(err)
  6. }
  7. http.ListenAndServe(":8080", app)
  8. }

注意,在将其用作http.Handler之前,应该手动调用其构建方法来构建应用程序和路由器。
另一个例子:

  1. func main() {
  2. app := iris.New()
  3. // [...routes]
  4. app.Build()
  5. srv := &http.Server{
  6. Addr: ":8080",
  7. Handler: app,
  8. ReadTimeout: 10 * time.Second,
  9. WriteTimeout: 10 * time.Second,
  10. MaxHeaderBytes: 1 << 20,
  11. }
  12. srv.ListenAndServe()
  13. }

但是,您很少需要外部http。服务器实例与Iris。您可以通过应用程序使用任何tcp侦听器、http服务器或自定义函数进行侦听。运行方法。

  1. app.Run(iris.Listener(l net.Listener)) // listen using a custom net.Listener
  2. app.Run(iris.Server(srv *http.Server)) // listen using a custom http.Server
  3. app.Run(iris.Addr(addr string)) // the app.Listen is a shortcut of this method.
  4. app.Run(iris.TLS(addr string, certFileOrContents, keyFileOrContents string)) // listen TLS.
  5. app.Run(iris.AutoTLS(addr, domain, email string)) // listen using letsencrypt (see below).
  6. // and any custom function that returns an error:
  7. app.Run(iris.Raw(f func() error))

socket 分区

此选项允许在多cpu服务器上线性扩展服务器性能。详情请参阅https://www.nginx.com/blog/soct-sharing-nginx-rele-1-9-1/。iris.WithSocketSharding配置器。

示例代码:

  1. package main
  2. import (
  3. "time"
  4. "github.com/kataras/iris/v12"
  5. )
  6. func main() {
  7. startup := time.Now()
  8. app := iris.New()
  9. app.Get("/", func(ctx iris.Context) {
  10. s := startup.Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat())
  11. ctx.Writef("This server started at: %s\n", s)
  12. })
  13. app.Listen(":8080", iris.WithSocketSharding)
  14. // or app.Run(..., iris.WithSocketSharding)
  15. }

支持的加密

1行LetsEncrypt HTTPS服务器的例子。

  1. package main
  2. import (
  3. "log"
  4. "github.com/iris-gonic/autotls"
  5. "github.com/kataras/iris/v12"
  6. )
  7. func main() {
  8. app := iris.Default()
  9. // Ping handler
  10. app.Get("/ping", func(ctx iris.Context) {
  11. ctx.WriteString("pong")
  12. })
  13. app.Run(iris.AutoTLS(":443", "example.com example2.com", "mail@example.com"))
  14. }

自定义TLS的例子(你也可以绑定一个autocert管理器):

  1. app.Run(
  2. iris.TLS(":443", "", "", func(su *iris.Supervisor) {
  3. su.Server.TLSConfig = &tls.Config{
  4. /* your custom fields */
  5. },
  6. }),
  7. )

所有的iris.Runner方法,如:Addr, TLS, AutoTLS, Server, Listener和e.t.c接受func(*iris.Supervisor)的可变输入参数来配置http服务器实例的构建状态。

使用Iris运行多个服务

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "time"
  6. "github.com/kataras/iris/v12"
  7. "github.com/kataras/iris/v12/middleware/recover"
  8. "golang.org/x/sync/errgroup"
  9. )
  10. var g errgroup.Group
  11. func startApp1() error {
  12. app := iris.New().SetName("app1")
  13. app.Use(recover.New())
  14. app.Get("/", func(ctx iris.Context) {
  15. app.Get("/", func(ctx iris.Context) {
  16. ctx.JSON(iris.Map{
  17. "code": iris.StatusOK,
  18. "message": "Welcome server 1",
  19. })
  20. })
  21. })
  22. app.Build()
  23. return app.Listen(":8080")
  24. }
  25. func startApp2() error {
  26. app := iris.New().SetName("app2")
  27. app.Use(recover.New())
  28. app.Get("/", func(ctx iris.Context) {
  29. ctx.JSON(iris.Map{
  30. "code": iris.StatusOK,
  31. "message": "Welcome server 2",
  32. })
  33. })
  34. return app.Listen(":8081")
  35. }
  36. func main() {
  37. g.Go(startApp1)
  38. g.Go(startApp2)
  39. if err := g.Wait(); err != nil {
  40. log.Fatal(err)
  41. }
  42. }

通过应用程序包管理多个Iris实例。点击这里了解更多内容。

优雅关机或重启

有一些方法可以用来执行优雅的关闭或重新启动。你可以使用专门为此而构建的第三方软件包,或者您可以使用app.Shutdown(context.Context)方法。例子可以在这里找到。

注册一个事件在CTRL/CMD+C使用iris.RegisterOnInterrupt:

  1. idleConnsClosed := make(chan struct{})
  2. iris.RegisterOnInterrupt(func() {
  3. timeout := 10 * time.Second
  4. ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
  5. defer cancel()
  6. // close all hosts.
  7. app.Shutdown(ctx)
  8. close(idleConnsClosed)
  9. })
  10. // [...]
  11. app.Listen(":8080", iris.WithoutInterruptHandler, iris.WithoutServerError(iris.ErrServerClosed))
  12. <-idleConnsClosed

使用模板构建单个二进制文件

通过使用[go-bindata][https://github.com/go-bindata/go-bindata]的AssetFile生成函数,可以将服务器构建为包含模板的单个二进制文件。

  1. $ go get -u github.com/go-bindata/go-bindata/...
  2. $ go-bindata -fs -prefix "templates" ./templates/...
  3. $ go run .

示例代码:

  1. func main() {
  2. app := iris.New()
  3. tmpl := iris.HTML(AssetFile(), ".html")
  4. tmpl.Layout("layouts/layout.html")
  5. tmpl.AddFunc("greet", func(s string) string {
  6. return "Greetings " + s + "!"
  7. })
  8. app.RegisterView(tmpl)
  9. // [...]
  10. }

参见_examples/view中的完整示例。

尝试将body绑定到不同的结构中

绑定请求体的常规方法使用ctx.Request()。主体和他们不能被称为多次,除非iris.WithoutBodyConsumptionOnUnmarshal配置器被传递给app.Run/Listen。

  1. package main
  2. import "github.com/kataras/iris/v12"
  3. func main() {
  4. app := iris.New()
  5. app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
  6. // body, err := ioutil.ReadAll(ctx.Request().Body) once or
  7. body, err := ctx.GetBody() // as many times as you need.
  8. if err != nil {
  9. ctx.StopWithError(iris.StatusInternalServerError, err)
  10. return
  11. }
  12. if len(body) == 0 {
  13. ctx.WriteString(`The body was empty.`)
  14. } else {
  15. ctx.WriteString("OK body is still:\n")
  16. ctx.Write(body)
  17. }
  18. })
  19. app.Listen(":8080", iris.WithoutBodyConsumptionOnUnmarshal)
  20. }
  21. func logAllBody(ctx iris.Context) {
  22. body, err := ctx.GetBody()
  23. if err == nil && len(body) > 0 {
  24. ctx.Application().Logger().Infof("logAllBody: %s", string(body))
  25. }
  26. ctx.Next()
  27. }
  28. func logJSON(ctx iris.Context) {
  29. var p interface{}
  30. if err := ctx.ReadJSON(&p); err == nil {
  31. ctx.Application().Logger().Infof("logJSON: %#+v", p)
  32. }
  33. ctx.Next()
  34. }
  35. func logFormValues(ctx iris.Context) {
  36. values := ctx.FormValues()
  37. if values != nil {
  38. ctx.Application().Logger().Infof("logFormValues: %v", values)
  39. }
  40. ctx.Next()
  41. }

可以使用ReadBody根据客户机的内容类型将结构绑定到请求。您还可以使用内容协商。这里有一个完整的例子:

  1. package main
  2. import (
  3. "github.com/kataras/iris/v12"
  4. )
  5. func main() {
  6. app := newApp()
  7. // See main_test.go for usage.
  8. app.Listen(":8080")
  9. }
  10. func newApp() *iris.Application {
  11. app := iris.New()
  12. // To automatically decompress using gzip:
  13. // app.Use(iris.GzipReader)
  14. app.Use(setAllowedResponses)
  15. app.Post("/", readBody)
  16. return app
  17. }
  18. type payload struct {
  19. Message string `json:"message" xml:"message" msgpack:"message" yaml:"Message" url:"message" form:"message"`
  20. }
  21. func readBody(ctx iris.Context) {
  22. var p payload
  23. // Bind request body to "p" depending on the content-type that client sends the data,
  24. // e.g. JSON, XML, YAML, MessagePack, Protobuf, Form and URL Query.
  25. err := ctx.ReadBody(&p)
  26. if err != nil {
  27. ctx.StopWithProblem(iris.StatusBadRequest,
  28. iris.NewProblem().Title("Parser issue").Detail(err.Error()))
  29. return
  30. }
  31. // For the sake of the example, log the received payload.
  32. ctx.Application().Logger().Infof("Received: %#+v", p)
  33. // Send back the payload depending on the accept content type and accept-encoding of the client,
  34. // e.g. JSON, XML and so on.
  35. ctx.Negotiate(p)
  36. }
  37. func setAllowedResponses(ctx iris.Context) {
  38. // Indicate that the Server can send JSON, XML, YAML and MessagePack for this request.
  39. ctx.Negotiation().JSON().XML().YAML().MsgPack()
  40. // Add more, allowed by the server format of responses, mime types here...
  41. // If client is missing an "Accept: " header then default it to JSON.
  42. ctx.Negotiation().Accept.JSON()
  43. ctx.Next()
  44. }


HTTP2服务器推送

完整的示例代码可以在_examples/response-writer/http2push中找到。
服务器推送让服务器在用户没有明确要求的情况下,先发制人地将网站资产“推送”给客户端。如果小心使用,我们可以发送我们知道用户将需要的页面,他们正在请求。

  1. package main
  2. import (
  3. "net/http"
  4. "github.com/kataras/iris/v12"
  5. )
  6. func main() {
  7. app := iris.New()
  8. app.Get("/", pushHandler)
  9. app.Get("/main.js", simpleAssetHandler)
  10. app.Run(iris.TLS("127.0.0.1:443", "mycert.crt", "mykey.key"))
  11. // $ openssl req -new -newkey rsa:4096 -x509 -sha256 \
  12. // -days 365 -nodes -out mycert.crt -keyout mykey.key
  13. }
  14. func pushHandler(ctx iris.Context) {
  15. // The target must either be an absolute path (like "/path") or an absolute
  16. // URL that contains a valid host and the same scheme as the parent request.
  17. // If the target is a path, it will inherit the scheme and host of the
  18. // parent request.
  19. target := "/main.js"
  20. if pusher, ok := ctx.ResponseWriter().Naive().(http.Pusher); ok {
  21. err := pusher.Push(target, nil)
  22. if err != nil {
  23. if err == iris.ErrPushNotSupported {
  24. ctx.StopWithText(iris.StatusHTTPVersionNotSupported, "HTTP/2 push not supported.")
  25. } else {
  26. ctx.StopWithError(iris.StatusInternalServerError, err)
  27. }
  28. return
  29. }
  30. }
  31. ctx.HTML(`<html><body><script src="%s"></script></body></html>`, target)
  32. }
  33. func simpleAssetHandler(ctx iris.Context) {
  34. ctx.ServeFile("./public/main.js")
  35. }

设置和获取cookie

安全cookie,编码和解码,会话(和会话缩放),flash消息和更多可以在_examples/cookies_examples/sessions目录中找到。

  1. import "github.com/kataras/iris/v12"
  2. func main() {
  3. app := iris.Default()
  4. app.Get("/cookie", func(ctx iris.Context) {
  5. value := ctx.GetCookie("my_cookie")
  6. if value == "" {
  7. value = "NotSet"
  8. ctx.SetCookieKV("my_cookie", value)
  9. // Alternatively: ctx.SetCookie(&http.Cookie{...})
  10. ctx.SetCookie("", "test", 3600, "/", "localhost", false, true)
  11. }
  12. ctx.Writef("Cookie value: %s \n", cookie)
  13. })
  14. app.Listen(":8080")
  15. }

如果你想自定义路径:

  1. ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored"))

如果你想只对当前请求路径可见:

  1. ctx.SetCookieKV(name, value, iris.CookieCleanPath /* or iris.CookiePath("") */)

More:

  • iris.CookieAllowReclaim
  • iris.CookieAllowSubdomains
  • iris.CookieSecure
  • iris.CookieHTTPOnly
  • iris.CookieSameSite
  • iris.CookiePath
  • iris.CookieCleanPath
  • iris.CookieExpires
  • iris.CookieEncoding

你也可以在一个中间件中为整个请求添加cookie选项:

  1. func setCookieOptions(ctx iris.Context) {
  2. ctx.AddCookieOptions(iris.CookieHTTPOnly(true), iris.CookieExpires(1*time.Hour))
  3. ctx.Next()
  4. }

测试


Iris为httpexpect (web应用程序的测试框架)提供了令人难以置信的支持。iris/httptest子包为iris + httpexpect提供了帮助程序。

如果您喜欢Go的标准net/http/httptest包,您仍然可以使用它。因为每个http web框架都与任何外部测试工具兼容,所以最终它就是http。

测试基本身份验证

在第一个示例中,我们将使用iris/httptest测试基本身份验证。

1.main.go源文件看起来是这样的:

  1. package main
  2. import (
  3. "github.com/kataras/iris/v12"
  4. "github.com/kataras/iris/v12/middleware/basicauth"
  5. )
  6. func newApp() *iris.Application {
  7. app := iris.New()
  8. authConfig := basicauth.Config{
  9. Users: map[string]string{"myusername": "mypassword"},
  10. }
  11. authentication := basicauth.New(authConfig)
  12. app.Get("/", func(ctx iris.Context) { ctx.Redirect("/admin") })
  13. needAuth := app.Party("/admin", authentication)
  14. {
  15. //http://localhost:8080/admin
  16. needAuth.Get("/", h)
  17. // http://localhost:8080/admin/profile
  18. needAuth.Get("/profile", h)
  19. // http://localhost:8080/admin/settings
  20. needAuth.Get("/settings", h)
  21. }
  22. return app
  23. }
  24. func h(ctx iris.Context) {
  25. username, password, _ := ctx.Request().BasicAuth()
  26. // third parameter ^ will be always true because the middleware
  27. // makes sure for that, otherwise this handler will not be executed.
  28. ctx.Writef("%s %s:%s", ctx.Path(), username, password)
  29. }
  30. func main() {
  31. app := newApp()
  32. app.Listen(":8080")
  33. }
  1. 现在,创建一个main_test.go。点击“文件”并复制粘贴以下内容。 ```go package main

import ( “testing”

  1. "github.com/kataras/iris/v12/httptest"

)

func TestNewApp(t *testing.T) { app := newApp() e := httptest.New(t, app)

  1. // redirects to /admin without basic auth
  2. e.GET("/").Expect().Status(httptest.StatusUnauthorized)
  3. // without basic auth
  4. e.GET("/admin").Expect().Status(httptest.StatusUnauthorized)
  5. // with valid basic auth
  6. e.GET("/admin").WithBasicAuth("myusername", "mypassword").Expect().
  7. Status(httptest.StatusOK).Body().Equal("/admin myusername:mypassword")
  8. e.GET("/admin/profile").WithBasicAuth("myusername", "mypassword").Expect().
  9. Status(httptest.StatusOK).Body().Equal("/admin/profile myusername:mypassword")
  10. e.GET("/admin/settings").WithBasicAuth("myusername", "mypassword").Expect().
  11. Status(httptest.StatusOK).Body().Equal("/admin/settings myusername:mypassword")
  12. // with invalid basic auth
  13. e.GET("/admin/settings").WithBasicAuth("invalidusername", "invalidpassword").
  14. Expect().Status(httptest.StatusUnauthorized)

}

  1. 3.打开命令行并执行:
  2. ```shell
  3. $ go test -v

测试cookie

  1. package main
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/kataras/iris/v12/httptest"
  6. )
  7. func TestCookiesBasic(t *testing.T) {
  8. app := newApp()
  9. e := httptest.New(t, app, httptest.URL("http://example.com"))
  10. cookieName, cookieValue := "my_cookie_name", "my_cookie_value"
  11. // Test Set A Cookie.
  12. t1 := e.GET(fmt.Sprintf("/cookies/%s/%s", cookieName, cookieValue)).
  13. Expect().Status(httptest.StatusOK)
  14. // Validate cookie's existence, it should be available now.
  15. t1.Cookie(cookieName).Value().Equal(cookieValue)
  16. t1.Body().Contains(cookieValue)
  17. path := fmt.Sprintf("/cookies/%s", cookieName)
  18. // Test Retrieve A Cookie.
  19. t2 := e.GET(path).Expect().Status(httptest.StatusOK)
  20. t2.Body().Equal(cookieValue)
  21. // Test Remove A Cookie.
  22. t3 := e.DELETE(path).Expect().Status(httptest.StatusOK)
  23. t3.Body().Contains(cookieName)
  24. t4 := e.GET(path).Expect().Status(httptest.StatusOK)
  25. t4.Cookies().Empty()
  26. t4.Body().Empty()
  27. }
  1. $ go test -v -run=TestCookiesBasic$

Iris web框架本身使用这个包来测试自己。在_examples存储库目录中,您还可以找到一些有用的测试。要了解更多信息,请查看和阅读httpexpect的文档

本地化


介绍

本地化特性提供了一种方便的方法来检索各种语言中的字符串,从而使您可以轻松地在应用程序中支持多种语言。语言字符串存储在。/locale目录中的文件中。在这个目录下,应用程序支持的每种语言都有一个子目录:

  1. main.go
  2. └───locales
  3. ├───el-GR
  4. home.yml
  5. ├───en-US
  6. home.yml
  7. └───zh-CN
  8. home.yml

应用程序的默认语言是第一种注册语言。

  1. app := iris.New()
  2. // First parameter: Glob filpath patern,
  3. // Second variadic parameter: Optional language tags,
  4. // the first one is the default/fallback one.
  5. app.I18n.Load("./locales/*/*", "en-US", "el-GR", "zh-CN")

或者如果你加载所有语言通过:

  1. app.I18n.Load("./locales/*/*")
  2. // Then set the default language using:
  3. app.I18n.SetDefault("en-US")

负载嵌入式部分

您可能希望在应用程序可执行文件中使用go-bindata工具嵌入区域设置。

  1. 安装一个 go-bindata 工具。例如:
    1. $ go get -u github.com/go-bindata/go-bindata/...
    2.将本地文件嵌入到应用程序中
    1. $ go-bindata -o locales.go ./locales/...
    3.使用LoadAssets方法初始化和加载语言
    ^资产名称和资产函数是由go-bindata生成的
    1. ap.I18n.LoadAssets(AssetNames, Asset, "en-US", "el-GR", "zh-CN")

定义翻译

语言环境文件可以用YAML(推荐)、JSON、TOML或INI格式编写。
每个文件都应该包含密钥。键也可以有子键(我们称它们为“节”)。
每个键的值应该是由其翻译文本(或模板)或/及其复数键值包含的形式字符串或映射。

Iris i18n模块支持开箱即用的多元化,见下面。

Fmt风格

  1. hi: "Hi %s!"
  1. ctx.Tr("Hi", "John")
  2. // Outputs: Hi John!

多元化

Iris i18n支持复数变量。要定义按地区设置的变量,必须定义Vars键的一个新部分。
变量可接受的键值是:

  • one
  • “=x” where x is a number
  • “<x”
  • other
  • format

例子:

  1. Vars:
  2. - Minutes:
  3. one: "minute"
  4. other: "minutes"
  5. - Houses:
  6. one: "house"
  7. other: "houses"

然后,每条消息都可以使用这个变量,如下所示:

  1. # Using variables in raw string
  2. YouLate: "You are %[1]d ${Minutes} late."
  3. # [x] is the argument position,
  4. # variables always have priority other fmt-style arguments,
  5. # that's why we see [1] for houses and [2] for the string argument.
  6. HouseCount: "%[2]s has %[1]d ${Houses}."
  1. ctx.Tr("YouLate", 1)
  2. // Outputs: You are 1 minute late.
  3. ctx.Tr("YouLate", 10)
  4. // Outputs: You are 10 minutes late.
  5. ctx.Tr("HouseCount", 2, "John")
  6. // Outputs: John has 2 houses.

您可以选择什么消息将显示基于给定的复数计数。
除了变量,每个消息也可以有其复数形式!
可接受的钥匙:

  • zero
  • one
  • two
  • “=x”
  • “<x”
  • “>x”
  • other

让我们创建一个简单的多特性消息,它也可以使用我们在上面创建的Minutes变量。

  1. FreeDay:
  2. "=3": "You have three days and %[2]d ${Minutes} off." # "FreeDay" 3, 15
  3. one: "You have a day off." # "FreeDay", 1
  4. other: "You have %[1]d free days." # "FreeDay", 5
  1. ctx.Tr("FreeDay", 3, 15)
  2. // Outputs: You have three days and 15 minutes off.
  3. ctx.Tr("FreeDay", 1)
  4. // Outputs: You have a day off.
  5. ctx.Tr("FreeDay", 5)
  6. // Outputs: You have 5 free days.

让我们继续使用更高级的示例,使用模板文本+函数+复数+变量。

  1. Vars:
  2. - Houses:
  3. one: "house"
  4. other: "houses"
  5. - Gender:
  6. "=1": "She"
  7. "=2": "He"
  8. VarTemplatePlural:
  9. one: "${Gender} is awesome!"
  10. other: "other (${Gender}) has %[3]d ${Houses}."
  11. "=5": "{{call .InlineJoin .Names}} are awesome."
  1. const (
  2. female = iota + 1
  3. male
  4. )
  5. ctx.Tr("VarTemplatePlural", iris.Map{
  6. "PluralCount": 5,
  7. "Names": []string{"John", "Peter"},
  8. "InlineJoin": func(arr []string) string {
  9. return strings.Join(arr, ", ")
  10. },
  11. })
  12. // Outputs: John, Peter are awesome
  13. ctx.Tr("VarTemplatePlural", 1, female)
  14. // Outputs: She is awesome!
  15. ctx.Tr("VarTemplatePlural", 2, female, 5)
  16. // Outputs: other (She) has 5 houses.

分片

如果键不是预留的(例如,1,two…),那么它就充当子节。各部分由点字符(.)分隔。

  1. Welcome:
  2. Message: "Welcome {{.Name}}"
  1. ctx.Tr("Welcome.Message", iris.Map{"Name": "John"})
  2. // Outputs: Welcome John

确定当前区域设置

你可以使用context.GetLocale。方法来确定当前语言环境或检查语言环境是否为给定值:

  1. func(ctx iris.Context) {
  2. locale := ctx.GetLocale()
  3. // [...]
  4. }

Locale接口如下所示。

  1. // Locale is the interface which returns from a `Localizer.GetLocale` metod.
  2. // It serves the transltions based on "key" or format. See `GetMessage`.
  3. type Locale interface {
  4. // Index returns the current locale index from the languages list.
  5. Index() int
  6. // Tag returns the full language Tag attached tothis Locale,
  7. // it should be uniue across different Locales.
  8. Tag() *language.Tag
  9. // Language should return the exact languagecode of this `Locale`
  10. //that the user provided on `New` function.
  11. //
  12. // Same as `Tag().String()` but it's static.
  13. Language() string
  14. // GetMessage should return translated text based n the given "key".
  15. GetMessage(key string, args ...interface{}) string
  16. }

检索翻译

使用context.Tr方法作为获取该请求的翻译文本的快捷方式。

  1. func(ctx iris.Context) {
  2. text := ctx.Tr("hi", "name")
  3. // [...]
  4. }

视图中使用

  1. func(ctx iris.Context) {
  2. ctx.View("index.html", iris.Map{
  3. "tr": ctx.Tr,
  4. })
  5. }

例子

  1. package main
  2. import (
  3. "github.com/kataras/iris/v12"
  4. )
  5. func newApp() *iris.Application {
  6. app := iris.New()
  7. // Configure i18n.
  8. // First parameter: Glob filpath patern,
  9. // Second variadic parameter: Optional language tags, the first one is the default/fallback one.
  10. app.I18n.Load("./locales/*/*.ini", "en-US", "el-GR", "zh-CN")
  11. // app.I18n.LoadAssets for go-bindata.
  12. // Default values:
  13. // app.I18n.URLParameter = "lang"
  14. // app.I18n.Subdomain = true
  15. //
  16. // Set to false to disallow path (local) redirects,
  17. // see https://github.com/kataras/iris/issues/1369.
  18. // app.I18n.PathRedirect = true
  19. app.Get("/", func(ctx iris.Context) {
  20. hi := ctx.Tr("hi", "iris")
  21. locale := ctx.GetLocale()
  22. ctx.Writef("From the language %s translated output: %s", locale.Language(), hi)
  23. })
  24. app.Get("/some-path", func(ctx iris.Context) {
  25. ctx.Writef("%s", ctx.Tr("hi", "iris"))
  26. })
  27. app.Get("/other", func(ctx iris.Context) {
  28. language := ctx.GetLocale().Language()
  29. fromFirstFileValue := ctx.Tr("key1")
  30. fromSecondFileValue := ctx.Tr("key2")
  31. ctx.Writef("From the language: %s, translated output:\n%s=%s\n%s=%s",
  32. language, "key1", fromFirstFileValue,
  33. "key2", fromSecondFileValue)
  34. })
  35. // using in inside your views:
  36. view := iris.HTML("./views", ".html")
  37. app.RegisterView(view)
  38. app.Get("/templates", func(ctx iris.Context) {
  39. ctx.View("index.html", iris.Map{
  40. "tr": ctx.Tr, // word, arguments... {call .tr "hi" "iris"}}
  41. })
  42. // Note that,
  43. // Iris automatically adds a "tr" global template function as well,
  44. // the only difference is the way you call it inside your templates and
  45. // that it accepts a language code as its first argument.
  46. })
  47. //
  48. return app
  49. }
  50. func main() {
  51. app := newApp()
  52. // go to http://localhost:8080/el-gr/some-path
  53. // ^ (by path prefix)
  54. //
  55. // or http://el.mydomain.com8080/some-path
  56. // ^ (by subdomain - test locally with the hosts file)
  57. //
  58. // or http://localhost:8080/zh-CN/templates
  59. // ^ (by path prefix with uppercase)
  60. //
  61. // or http://localhost:8080/some-path?lang=el-GR
  62. // ^ (by url parameter)
  63. //
  64. // or http://localhost:8080 (default is en-US)
  65. // or http://localhost:8080/?lang=zh-CN
  66. //
  67. // go to http://localhost:8080/other?lang=el-GR
  68. // or http://localhost:8080/other (default is en-US)
  69. // or http://localhost:8080/other?lang=en-US
  70. //
  71. // or use cookies to set the language.
  72. app.Listen(":8080", iris.WithSitemap("http://localhost:8080"))
  73. }

站点地图

如果app.I18n,站点地图翻译会根据路径前缀自动设置每个路由。如果app.I18n,则PathRedirect为true或by子域。如果app.I18n.子域名为真或按URL查询参数。URLParameter不是空的。

更多信息请访问:https://support.google.com/webmasters/answer/189077?hl=en

  1. GET http://localhost:8080/sitemap.xml
  1. <?xml version="1.0" encoding="utf-8" standalone="yes"?>
  2. <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
  3. <url>
  4. <loc>http://localhost:8080/</loc>
  5. <xhtml:link rel="alternate" hreflang="en-US" href="http://localhost:8080/"></xhtml:link>
  6. <xhtml:link rel="alternate" hreflang="el-GR" href="http://localhost:8080/el-GR/"></xhtml:link>
  7. <xhtml:link rel="alternate" hreflang="zh-CN" href="http://localhost:8080/zh-CN/"></xhtml:link>
  8. </url>
  9. <url>
  10. <loc>http://localhost:8080/some-path</loc>
  11. <xhtml:link rel="alternate" hreflang="en-US" href="http://localhost:8080/some-path"></xhtml:link>
  12. <xhtml:link rel="alternate" hreflang="el-GR" href="http://localhost:8080/el-GR/some-path"></xhtml:link>
  13. <xhtml:link rel="alternate" hreflang="zh-CN" href="http://localhost:8080/zh-CN/some-path"></xhtml:link>
  14. </url>
  15. <url>
  16. <loc>http://localhost:8080/other</loc>
  17. <xhtml:link rel="alternate" hreflang="en-US" href="http://localhost:8080/other"></xhtml:link>
  18. <xhtml:link rel="alternate" hreflang="el-GR" href="http://localhost:8080/el-GR/other"></xhtml:link>
  19. <xhtml:link rel="alternate" hreflang="zh-CN" href="http://localhost:8080/zh-CN/other"></xhtml:link>
  20. </url>
  21. <url>
  22. <loc>http://localhost:8080/templates</loc>
  23. <xhtml:link rel="alternate" hreflang="en-US" href="http://localhost:8080/templates"></xhtml:link>
  24. <xhtml:link rel="alternate" hreflang="el-GR" href="http://localhost:8080/el-GR/templates"></xhtml:link>
  25. <xhtml:link rel="alternate" hreflang="zh-CN" href="http://localhost:8080/zh-CN/templates"></xhtml:link>
  26. </url>
  27. </urlset>

这就是关于Iris的所有基本知识。对于初学者来说,这个文档已经涵盖了足够多的内容。想成为一个专家和认证的Iris开发者,学习MVC, i18n,依赖注入,gRPC, lambda函数,websockets,最佳实践和更多?今天索取Iris电子书,参与Iris的开发!