安装
Iris是一个跨平台的软件。
唯一的要求是 Go 编程语言,版本 1.20 及更高版本。
$ mkdir myapp $ cd myapp $ go mod init myapp $ go get github.com/kataras/iris/v12@latest
将其导入到代码中:
import "github.com/kataras/iris/v12"
故障 排除
如果在安装过程中遇到网络错误,请确保设置了有效的 GOPROXY 环境变量。
go env -w GOPROXY=https://goproxy.io,direct
如果上述方法均无效,请清理 go 模块缓存:
go clean --modcache
快速入门
# assume the following codes in main.go file $ cat main.go
package main import "github.com/kataras/iris/v12" func main() { app := iris.New() booksAPI := app.Party("/books") { booksAPI.Use(iris.Compression) // GET: http://localhost:8080/books booksAPI.Get("/", list) // POST: http://localhost:8080/books booksAPI.Post("/", create) } app.Listen(":8080") } // Book example. type Book struct { Title string `json:"title"` } func list(ctx iris.Context) { books := []Book{ {"Mastering Concurrency in Go"}, {"Go Design Patterns"}, {"Black Hat Go"}, } ctx.JSON(books) // TIP: negotiate the response between server's prioritizes // and client's requirements, instead of ctx.JSON: // ctx.Negotiation().JSON().MsgPack().Protobuf() // ctx.Negotiate(books) } func create(ctx iris.Context) { var b Book err := ctx.ReadJSON(&b) // TIP: use ctx.ReadBody(&b) to bind // any type of incoming data instead. if err != nil { ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem(). Title("Book creation failure").DetailErr(err)) // TIP: use ctx.StopWithError(code, err) when only // plain text responses are expected on errors. return } println("Received Book: " + b.Title) ctx.StatusCode(iris.StatusCreated) }
MVC 等效项:
import "github.com/kataras/iris/v12/mvc"
m := mvc.New(booksAPI) m.Handle(new(BookController))
type BookController struct { /* dependencies */ } // GET: http://localhost:8080/books func (c *BookController) Get() []Book { return []Book{ {"Mastering Concurrency in Go"}, {"Go Design Patterns"}, {"Black Hat Go"}, } } // POST: http://localhost:8080/books func (c *BookController) Post(b Book) int { println("Received Book: " + b.Title) return iris.StatusCreated }
运行您的鸢尾花网络服务器:
$ go run main.go > Now listening on: http://localhost:8080 > Application started. Press CTRL+C to shut down.
列表书:
$ curl --header 'Accept-Encoding:gzip' http://localhost:8080/books [ { "title": "Mastering Concurrency in Go" }, { "title": "Go Design Patterns" }, { "title": "Black Hat Go" } ]
创建新图书:
$ curl -i -X POST \ --header 'Content-Encoding:gzip' \ --header 'Content-Type:application/json' \ --data "{\"title\":\"Writing An Interpreter In Go\"}" \ http://localhost:8080/books > HTTP/1.1 201 Created
这就是错误响应的样子:
$ curl -X POST --data "{\"title\" \"not valid one\"}" \ http://localhost:8080/books > HTTP/1.1 400 Bad Request { "status": 400, "title": "Book creation failure" "detail": "invalid character '\"' after object key", }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NL5y3Dps-1686647378212)(null)]
基准
Iris使用muxie的自定义版本。
📖 使用 int 的动态参数触发 200000 个请求,将 JSON 作为请求正文发送,并接收 JSON 作为响应。
名字 | 语言 | 要求/秒 | 延迟 | 吞吐量 | 完成时间 |
虹膜 | 去 | 238954 | 521.69乌秒 | 64.15兆字节 | 0.84秒 |
琴酒 | 去 | 229665 | 541.96乌秒 | 62.86兆字节 | 0.87秒 |
池 | 去 | 228072 | 545.78乌秒 | 62.61兆字节 | 0.88秒 |
回波 | 去 | 224491 | 553.84乌秒 | 61.70兆字节 | 0.89秒 |
马提尼酒 | 去 | 198166 | 627.46乌秒 | 54.47兆字节 | 1.01秒 |
茶隼 | C# | 163486 | 766.90乌秒 | 47.42兆字节 | 1.23秒 |
水牛 | 去 | 102478 | 1.22毫秒 | 28.14兆字节 | 1.95秒 |
科阿 | 爪哇语 | 48425 | 2.56毫秒 | 15.39兆字节 | 4.14秒 |
表达 | 爪哇语 | 23622 | 5.25毫秒 | 9.04兆字节 | 8.41秒 |
接口示例
您可以在 Iris 示例存储库中找到许多随时可以运行的示例。
使用获取、发布、放置、修补、删除和选项
func main() { // Creates an iris application with default middleware: // Default with "debug" Logger Level. // Localization enabled on "./locales" directory // and HTML templates on "./views" or "./templates" directory. // It runs with the AccessLog on "./access.log", // Recovery (crash-free) and Request ID middleware already attached. app := iris.Default() app.Get("/someGet", getting) app.Post("/somePost", posting) app.Put("/somePut", putting) app.Delete("/someDelete", deleting) app.Patch("/somePatch", patching) app.Header("/someHead", head) app.Options("/someOptions", options) app.Listen(":8080") }
路径中的参数
func main() { app := iris.Default() // This handler will match /user/john but will not match /user/ or /user app.Get("/user/{name}", func(ctx iris.Context) { name := ctx.Params().Get("name") ctx.Writef("Hello %s", name) }) // However, this one will match /user/john/ and also /user/john/send // If no other routers match /user/john, it will redirect to /user/john/ app.Get("/user/{name}/{action:path}", func(ctx iris.Context) { name := ctx.Params().Get("name") action := ctx.Params().Get("action") message := name + " is " + action ctx.WriteString(message) }) // For each matched request Context will hold the route definition app.Post("/user/{name:string}/{action:path}", func(ctx iris.Context) { ctx.GetCurrentRoute().Tmpl().Src == "/user/{name:string}/{action:path}" // true }) app.Listen(":8080") }
内置可用参数类型:
参数类型 | 去类型 | 验证 | 检索帮助程序 |
:string |
字符串 | 任何(单路径段) | Params().Get |
:uuid |
字符串 | uuidv4 或 v1(单路径段) | Params().Get |
:int |
国际 | -9223372036854775808 到 9223372036854775807 (x64) 或 -2147483648 到 2147483647 (x32),取决于主机架构 | Params().GetInt |
:int8 |
国际8 | -128 到 127 | Params().GetInt8 |
:int16 |
国际16 | -32768 到 32767 | Params().GetInt16 |
:int32 |
国际32 | -2147483648 到 2147483647 | Params().GetInt32 |
:int64 |
国际64 | -9223372036854775808 到 9223372036854775807 | Params().GetInt64 |
:uint |
乌因特 | 0 到 18446744073709551615 (x64) 或 0 到 4294967295 (x32),取决于主机架构 | Params().GetUint |
: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 |
布尔 | “1”或“t”或“T”或“真”或“真”或“真”或“0”或“f”或“F”或“假”或“假”或“假” | Params().GetBool |
:alphabetical |
字符串 | 小写或大写字母 | Params().Get |
:file |
字符串 | 小写或大写字母、数字、下划线 (_)、短划线 (-)、点 (.) 并且没有空格或其他对文件名无效的特殊字符 | Params().Get |
:path |
字符串 | 任何内容都可以用斜杠(路径段)分隔,但应该是路由路径的最后一部分 | Params().Get |
:mail |
字符串 | 未经域验证的电子邮件 | Params().Get |
:email |
字符串 | 具有域验证功能的电子邮件 | Params().Get |
:date |
字符串 | 年/月/日格式,例如 /博客/{参数:日期} 匹配 /博客/2022/04/21 | Params().GetTime 和Params().SimpleDate |
:weekday |
uint (0-6) 或字符串 | 时间串。工作日长名称格式(“星期日”到“星期一”或“星期日”到“星期一”)格式,例如 /schedule/{param:weekday} 匹配 /schedule/星期一 | Params().GetWeekday |
更多示例可在以下位置找到:_examples/路由。
查询字符串参数
func main() { app := iris.Default() // Query string parameters are parsed using the existing underlying request object. // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe app.Get("/welcome", func(ctx iris.Context) { firstname := ctx.URLParamDefault("firstname", "Guest") lastname := ctx.URLParam("lastname") // shortcut for ctx.Request().URL.Query().Get("lastname") ctx.Writef("Hello %s %s", firstname, lastname) }) app.Listen(":8080") }
多部分/乌伦编码形式
func main() { app := iris.Default() app.Post("/form_post", func(ctx iris.Context) { message := ctx.PostValue("message") nick := ctx.PostValueDefault("nick", "anonymous") ctx.JSON(iris.Map{ "status": "posted", "message": message, "nick": nick, }) }) app.Listen(":8080") }
再比如:查询+帖子表单
POST /post?id=1234&page=1 HTTP/1.1 Content-Type: application/x-www-form-urlencoded name=kataras&message=this_is_great
func main() { app := iris.Default() app.Post("/post", func(ctx iris.Context) { id, err := ctx.URLParamInt("id", 0) if err != nil { ctx.StopWithError(iris.StatusBadRequest, err) return } page := ctx.URLParamIntDefault("page", 0) name := ctx.PostValue("name") message := ctx.PostValue("message") ctx.Writef("id: %d; page: %d; name: %s; message: %s", id, page, name, message) }) app.Listen(":8080") }
id: 1234; page: 1; name: kataras; message: this_is_great
(adsbygoogle = window.adsbygoogle || []).push({});
查询和发布表单参数
POST /post?id=a&id=b&id=c&name=john&name=doe&name=kataras Content-Type: application/x-www-form-urlencoded
func main() { app := iris.Default() app.Post("/post", func(ctx iris.Context) { ids := ctx.URLParamSlice("id") names, err := ctx.PostValues("name") if err != nil { ctx.StopWithError(iris.StatusBadRequest, err) return } ctx.Writef("ids: %v; names: %v", ids, names) }) app.Listen(":8080") }
id [a b c], names: [john doe kataras]
上传文件
单个文件
const maxSize = 8 * iris.MB func main() { app := iris.Default() app.Post("/upload", func(ctx iris.Context) { // Set a lower memory limit for multipart forms (default is 32 MiB) ctx.SetMaxRequestBodySize(maxSize) // OR // app.Use(iris.LimitRequestBodySize(maxSize)) // OR // OR iris.WithPostMaxMemory(maxSize) // single file file, fileHeader, err:= ctx.FormFile("file") if err != nil { ctx.StopWithError(iris.StatusBadRequest, err) return } // Upload the file to specific destination. dest := filepath.Join("./uploads", fileHeader.Filename) ctx.SaveFormFile(fileHeader, dest) ctx.Writef("File: %s uploaded!", fileHeader.Filename) }) app.Listen(":8080") }
如何:curl
curl -X POST http://localhost:8080/upload \ -F "file=@/Users/kataras/test.zip" \ -H "Content-Type: multipart/form-data"
多个文件
请参阅详细的示例代码。
func main() { app := iris.Default() app.Post("/upload", func(ctx iris.Context) { files, n, err := ctx.UploadFormFiles("./uploads") if err != nil { ctx.StopWithStatus(iris.StatusInternalServerError) return } ctx.Writef("%d files of %d total size uploaded!", len(files), n)) }) app.Listen(":8080", iris.WithPostMaxMemory(8 * iris.MB)) }
如何:curl
curl -X POST http://localhost:8080/upload \ -F "upload[]=@/Users/kataras/test1.zip" \ -F "upload[]=@/Users/kataras/test2.zip" \ -H "Content-Type: multipart/form-data"
对路线进行分组
func main() { app := iris.Default() // Simple group: v1 v1 := app.Party("/v1") { v1.Post("/login", loginEndpoint) v1.Post("/submit", submitEndpoint) v1.Post("/read", readEndpoint) } // Simple group: v2 v2 := app.Party("/v2") { v2.Post("/login", loginEndpoint) v2.Post("/submit", submitEndpoint) v2.Post("/read", readEndpoint) } app.Listen(":8080") }
默认不带中间件的空白光圈
用
app := iris.New()
而不是
// Default with "debug" Logger Level. // Localization enabled on "./locales" directory // and HTML templates on "./views" or "./templates" directory. // It runs with the AccessLog on "./access.log", // Recovery and Request ID middleware already attached. app := iris.Default()
使用中间件
package main import ( "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/middleware/recover" ) func main() { // Creates an iris application without any middleware by default app := iris.New() // Global middleware using `UseRouter`. // // Recovery middleware recovers from any panics and writes a 500 if there was one. app.UseRouter(recover.New()) // Per route middleware, you can add as many as you desire. app.Get("/benchmark", MyBenchLogger(), benchEndpoint) // Authorization group // authorized := app.Party("/", AuthRequired()) // exactly the same as: authorized := app.Party("/") // per group middleware! in this case we use the custom created // AuthRequired() middleware just in the "authorized" group. authorized.Use(AuthRequired()) { authorized.Post("/login", loginEndpoint) authorized.Post("/submit", submitEndpoint) authorized.Post("/read", readEndpoint) // nested group testing := authorized.Party("testing") testing.Get("/analytics", analyticsEndpoint) } // Listen and serve on 0.0.0.0:8080 app.Listen(":8080") }
(adsbygoogle = window.adsbygoogle || []).push({});
应用程序文件记录器
func main() { app := iris.Default() // Logging to a file. // Colors are automatically disabled when writing to a file. f, _ := os.Create("iris.log") app.Logger().SetOutput(f) // Use the following code if you need to write the logs // to file and console at the same time. // app.Logger().AddOutput(os.Stdout) app.Get("/ping", func(ctx iris.Context) { ctx.WriteString("pong") }) app.Listen(":8080") }
控制日志输出着色
默认情况下,控制台上的日志输出应根据检测到的 TTY 进行着色。
自定义关卡标题,文本,颜色和样式。
导入和 :golog``pio
import ( "github.com/kataras/golog" "github.com/kataras/pio" // [...] )
获取要自定义的级别,例如:DebugLevel
level := golog.Levels[golog.DebugLevel]
您可以完全控制他的文字、标题和风格:
// The Name of the Level // that named (lowercased) will be used // to convert a string level on `SetLevel` // to the correct Level type. Name string // AlternativeNames are the names that can be referred to this specific log level. // i.e Name = "warn" // AlternativeNames = []string{"warning"}, it's an optional field, // therefore we keep Name as a simple string and created this new field. AlternativeNames []string // Tha Title is the prefix of the log level. // See `ColorCode` and `Style` too. // Both `ColorCode` and `Style` should be respected across writers. Title string // ColorCode a color for the `Title`. ColorCode int // Style one or more rich options for the `Title`. Style []pio.RichOption
示例代码:
level := golog.Levels[golog.DebugLevel] level.Name = "debug" // default level.Title = "[DBUG]" // default level.ColorCode = pio.Yellow // default
要更改输出格式:
app.Logger().SetFormat("json", " ")
注册自定义格式化程序:
app.Logger().RegisterFormatter(new(myFormatter))
嘟嘟。格式化程序界面如下所示:
// Formatter is responsible to print a log to the logger's writer. type Formatter interface { // The name of the formatter. String() string // Set any options and return a clone, // generic. See `Logger.SetFormat`. Options(opts ...interface{}) Formatter // Writes the "log" to "dest" logger. Format(dest io.Writer, log *Log) bool }
要更改每个级别的输出和格式:
app.Logger().SetLevelOutput("error", os.Stderr) app.Logger().SetLevelFormat("json")
请求日志记录
我们在上面看到的应用程序记录器用于记录与应用程序相关的信息和错误。另一方面,我们在下面看到的访问记录器用于记录传入的HTTP请求和响应。
package main import ( "os" "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/middleware/accesslog" ) // Read the example and its comments carefully. func makeAccessLog() *accesslog.AccessLog { // Initialize a new access log middleware. ac := accesslog.File("./access.log") // Remove this line to disable logging to console: ac.AddOutput(os.Stdout) // The default configuration: ac.Delim = '|' ac.TimeFormat = "2006-01-02 15:04:05" ac.Async = false ac.IP = true ac.BytesReceivedBody = true ac.BytesSentBody = true ac.BytesReceived = false ac.BytesSent = false ac.BodyMinify = true ac.RequestBody = true ac.ResponseBody = false ac.KeepMultiLineError = true ac.PanicLog = accesslog.LogHandler // Default line format if formatter is missing: // Time|Latency|Code|Method|Path|IP|Path Params Query Fields|Bytes Received|Bytes Sent|Request|Response| // // Set Custom Formatter: ac.SetFormatter(&accesslog.JSON{ Indent: " ", HumanTime: true, }) // ac.SetFormatter(&accesslog.CSV{}) // ac.SetFormatter(&accesslog.Template{Text: "{{.Code}}"}) return ac } func main() { ac := makeAccessLog() defer ac.Close() // Close the underline file. app := iris.New() // Register the middleware (UseRouter to catch http errors too). app.UseRouter(ac.Handler) app.Get("/", indexHandler) app.Listen(":8080") } func indexHandler(ctx iris.Context) { ctx.WriteString("OK") }
阅读更多示例:_examples/logging/request-logger。
(adsbygoogle = window.adsbygoogle || []).push({});
模型绑定和验证
若要将请求正文绑定到类型中,请使用模型绑定。我们目前支持绑定、、、、和标准表单值(foo=bar&boo=baz)。JSON``JSONProtobuf``Protobuf``MsgPack``XML``YAML
ReadJSON(outPtr interface{}) error ReadJSONProtobuf(ptr proto.Message, opts ...ProtoUnmarshalOptions) error ReadProtobuf(ptr proto.Message) error ReadMsgPack(ptr interface{}) error ReadXML(outPtr interface{}) error ReadYAML(outPtr interface{}) error ReadForm(formObject interface{}) error ReadQuery(ptr interface{}) error
使用 时,Iris 会尝试根据内容类型标头推断绑定程序。如果您确定要绑定的内容,则可以使用特定方法,例如 或和等ReadBody``ReadXXX``ReadJSON``ReadProtobuf
ReadBody(ptr interface{}) error
明智的是,Iris没有内置的数据验证功能。但是,它确实允许您附加一个验证器,该验证器将自动调用诸如 , …在这个例子中,我们将学习如何使用 go-playground/validator/v10 进行请求正文验证。ReadJSON``ReadXML
请注意,您需要在要绑定的所有字段上设置相应的绑定标记。例如,从 JSON 绑定时,设置 .json:"fieldname"
您还可以指定特定字段为必填字段。如果字段在绑定时用空值修饰,并且值为空,则会返回错误。binding:"required"
package main import ( "fmt" "github.com/kataras/iris/v12" "github.com/go-playground/validator/v10" ) func main() { app := iris.New() app.Validator = validator.New() userRouter := app.Party("/user") { userRouter.Get("/validation-errors", resolveErrorsDocumentation) userRouter.Post("/", postUser) } app.Listen(":8080") } // User contains user information. type User struct { FirstName string `json:"fname" validate:"required"` LastName string `json:"lname" validate:"required"` Age uint8 `json:"age" validate:"gte=0,lte=130"` Email string `json:"email" validate:"required,email"` FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"` Addresses []*Address `json:"addresses" validate:"required,dive,required"` } // Address houses a users address information. type Address struct { Street string `json:"street" validate:"required"` City string `json:"city" validate:"required"` Planet string `json:"planet" validate:"required"` Phone string `json:"phone" validate:"required"` } type validationError struct { ActualTag string `json:"tag"` Namespace string `json:"namespace"` Kind string `json:"kind"` Type string `json:"type"` Value string `json:"value"` Param string `json:"param"` } func wrapValidationErrors(errs validator.ValidationErrors) []validationError { validationErrors := make([]validationError, 0, len(errs)) for _, validationErr := range errs { validationErrors = append(validationErrors, validationError{ ActualTag: validationErr.ActualTag(), Namespace: validationErr.Namespace(), Kind: validationErr.Kind().String(), Type: validationErr.Type().String(), Value: fmt.Sprintf("%v", validationErr.Value()), Param: validationErr.Param(), }) } return validationErrors } func postUser(ctx iris.Context) { var user User err := ctx.ReadJSON(&user) if err != nil { // Handle the error, below you will find the right way to do that... if errs, ok := err.(validator.ValidationErrors); ok { // Wrap the errors with JSON format, the underline library returns the errors as interface. validationErrors := wrapValidationErrors(errs) // Fire an application/json+problem response and stop the handlers chain. ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem(). Title("Validation error"). Detail("One or more fields failed to be validated"). Type("/user/validation-errors"). Key("errors", validationErrors)) return } // It's probably an internal JSON error, let's dont give more info here. ctx.StopWithStatus(iris.StatusInternalServerError) return } ctx.JSON(iris.Map{"message": "OK"}) } func resolveErrorsDocumentation(ctx iris.Context) { ctx.WriteString("A page that should document to web developers or users of the API on how to resolve the validation errors") }
样品请求
{ "fname": "", "lname": "", "age": 45, "email": "mail@example.com", "favColor": "#000", "addresses": [{ "street": "Eavesdown Docks", "planet": "Persphone", "phone": "none", "city": "Unknown" }] }
示例响应
{ "title": "Validation error", "detail": "One or more fields failed to be validated", "type": "http://localhost:8080/user/validation-errors", "status": 400, "fields": [ { "tag": "required", "namespace": "User.FirstName", "kind": "string", "type": "string", "value": "", "param": "" }, { "tag": "required", "namespace": "User.LastName", "kind": "string", "type": "string", "value": "", "param": "" } ] }
有关模型验证的更多信息,请访问:https://github.com/go-playground/validator/blob/master/_examples
绑定查询字符串
该方法仅绑定查询参数,而不绑定帖子数据,而是用于绑定帖子数据。ReadQuery``ReadForm
package main import "github.com/kataras/iris/v12" type Person struct { Name string `url:"name,required"` Address string `url:"address"` } func main() { app := iris.Default() app.Any("/", index) app.Listen(":8080") } func index(ctx iris.Context) { var person Person if err := ctx.ReadQuery(&person); err!=nil { ctx.StopWithError(iris.StatusBadRequest, err) return } ctx.Application().Logger().Infof("Person: %#+v", person) ctx.WriteString("Success") }
绑定任何
根据客户端发送数据的内容类型将请求正文绑定到“ptr”,例如 JSON、XML、YAML、MessagePack、Protobuf、Form 和 URL Query。
package main import ( "time" "github.com/kataras/iris/v12" ) type Person struct { Name string `form:"name" json:"name" url:"name" msgpack:"name"` Address string `form:"address" json:"address" url:"address" msgpack:"address"` Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1" json:"birthday" url:"birthday" msgpack:"birthday"` CreateTime time.Time `form:"createTime" time_format:"unixNano" json:"create_time" url:"create_time" msgpack:"createTime"` UnixTime time.Time `form:"unixTime" time_format:"unix" json:"unix_time" url:"unix_time" msgpack:"unixTime"` } func main() { app := iris.Default() app.Any("/", index) app.Listen(":8080") } func index(ctx iris.Context) { var person Person if err := ctx.ReadBody(&person); err!=nil { ctx.StopWithError(iris.StatusBadRequest, err) return } ctx.Application().Logger().Infof("Person: %#+v", person) ctx.WriteString("Success") }
测试它:
$ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
绑定网址路径参数
package main import "github.com/kataras/iris/v12" type myParams struct { Name string `param:"name"` Age int `param:"age"` Tail []string `param:"tail"` } // All parameters are required, as we already know, // the router will fire 404 if name or int or tail are missing. func main() { app := iris.Default() app.Get("/{name}/{age:int}/{tail:path}", func(ctx iris.Context) { var p myParams if err := ctx.ReadParams(&p); err != nil { ctx.StopWithError(iris.StatusInternalServerError, err) return } ctx.Writef("myParams: %#v", p) }) app.Listen(":8088") }
请求
$ curl -v http://localhost:8080/kataras/27/iris/web/framewor
(adsbygoogle = window.adsbygoogle || []).push({});
绑定标头
package main import "github.com/kataras/iris/v12" type myHeaders struct { RequestID string `header:"X-Request-Id,required"` Authentication string `header:"Authentication,required"` } func main() { app := iris.Default() r.GET("/", func(ctx iris.Context) { var hs myHeaders if err := ctx.ReadHeaders(&hs); err != nil { ctx.StopWithError(iris.StatusInternalServerError, err) return } ctx.JSON(hs) }) app.Listen(":8080") }
请求
curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \ http://localhost:8080
响应
{ "RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73", "Authentication": "Bearer my-token" }
“绑定 HTML ”复选框
package main import "github.com/kataras/iris/v12" func main() { app := iris.New() app.RegisterView(iris.HTML("./templates", ".html")) app.Get("/", showForm) app.Post("/", handleForm) app.Listen(":8080") } func showForm(ctx iris.Context) { if err := ctx.View("form.html"); err!=nil { ctx.HTML("<h3>%s</h3>", err.Error()) return } } type formExample struct { Colors []string `form:"colors[]"` // or just "colors". } func handleForm(ctx iris.Context) { var form formExample err := ctx.ReadForm(&form) if err != nil { ctx.StopWithError(iris.StatusBadRequest, err) return } ctx.JSON(iris.Map{"Colors": form.Colors}) }
templates/form.html
<form action="/" method="POST"> <p>Check one or more colors</p> <label for="red">Red</label> <!-- name can be "colors" too --> <input type="checkbox" name="colors[]" value="red" id="red"> <label for="green">Green</label> <input type="checkbox" name="colors[]" value="green" id="green"> <label for="blue">Blue</label> <input type="checkbox" name="colors[]" value="blue" id="blue"> <input type="submit"> </form>
响应
{ "Colors": [ "red", "green", "blue" ] }
JSON、JSONP、XML、Markdown、YAML 和 MsgPack 渲染
详细示例可在此处找到。
func main() { app := iris.New() // iris.Map is an alias of map[string]interface{} app.Get("/json", func(ctx iris.Context) { ctx.JSON(iris.Map{"message": "hello", "status": iris.StatusOK}) }) // Use Secure field to prevent json hijacking. // It prepends `"while(1),"` to the body when the data is array. app.Get("/json_secure", func(ctx iris.Context) { response := []string{"val1", "val2", "val3"} options := iris.JSON{Indent: "", Secure: true} ctx.JSON(response, options) // Will output: while(1);["val1","val2","val3"] }) // Use ASCII field to generate ASCII-only JSON // with escaped non-ASCII characters. app.Get("/json_ascii", func(ctx iris.Context) { response := iris.Map{"lang": "GO-虹膜", "tag": "<br>"} options := iris.JSON{Indent: " ", ASCII: true} ctx.JSON(response, options) /* Will output: { "lang": "GO-\u8679\u819c", "tag": "\u003cbr\u003e" } */ }) // Normally, JSON replaces special HTML characters with their unicode entities. // If you want to encode such characters literally, // you SHOULD set the UnescapeHTML field to true. app.Get("/json_raw", func(ctx iris.Context) { options := iris.JSON{UnescapeHTML: true} ctx.JSON(iris.Map{ "html": "<b>Hello, world!</b>", }, options) // Will output: {"html":"<b>Hello, world!</b>"} }) app.Get("/json_struct", func(ctx iris.Context) { // You also can use a struct. var msg struct { Name string `json:"user"` Message string Number int } msg.Name = "Mariah" msg.Message = "hello" msg.Number = 42 // Note that msg.Name becomes "user" in the JSON. // Will output: {"user": "Mariah", "Message": "hello", "Number": 42} ctx.JSON(msg) }) app.Get("/jsonp", func(ctx iris.Context) { ctx.JSONP(iris.Map{"hello": "jsonp"}, iris.JSONP{Callback: "callbackName"}) }) app.Get("/xml", func(ctx iris.Context) { ctx.XML(iris.Map{"message": "hello", "status": iris.StatusOK}) }) app.Get("/markdown", func(ctx iris.Context) { ctx.Markdown([]byte("# Hello Dynamic Markdown -- iris")) }) app.Get("/yaml", func(ctx iris.Context) { ctx.YAML(iris.Map{"message": "hello", "status": iris.StatusOK}) }) app.Get("/msgpack", func(ctx iris.Context) { u := User{ Firstname: "John", Lastname: "Doe", City: "Neither FBI knows!!!", Age: 25, } ctx.MsgPack(u) }) // Render using jsoniter instead of the encoding/json: app.Listen(":8080", iris.WithOptimizations) }
普罗托布夫
Iris 支持原生 protobuf with 和 protobuf to JSON 编码和解码。Protobuf
package main import ( "app/protos" "github.com/kataras/iris/v12" ) func main() { app := iris.New() app.Get("/", send) app.Get("/json", sendAsJSON) app.Post("/read", read) app.Post("/read_json", readFromJSON) app.Listen(":8080") } func send(ctx iris.Context) { response := &protos.HelloReply{Message: "Hello, World!"} ctx.Protobuf(response) } func sendAsJSON(ctx iris.Context) { response := &protos.HelloReply{Message: "Hello, World!"} options := iris.JSON{ Proto: iris.ProtoMarshalOptions{ AllowPartial: true, Multiline: true, Indent: " ", }, } ctx.JSON(response, options) } func read(ctx iris.Context) { var request protos.HelloRequest err := ctx.ReadProtobuf(&request) if err != nil { ctx.StopWithError(iris.StatusBadRequest, err) return } ctx.Writef("HelloRequest.Name = %s", request.Name) } func readFromJSON(ctx iris.Context) { var request protos.HelloRequest err := ctx.ReadJSONProtobuf(&request) if err != nil { ctx.StopWithError(iris.StatusBadRequest, err) return } ctx.Writef("HelloRequest.Name = %s", request.Name) }
提供静态文件
func main() { app := iris.New() app.Favicon("./resources/favicon.ico") app.HandleDir("/assets", iris.Dir("./assets")) app.Listen(":8080") }
该方法接受第三个可选参数:HandleDir``DirOptions
type DirOptions struct { // Defaults to "/index.html", if request path is ending with **/*/$IndexName // then it redirects to **/*(/) which another handler is handling it, // that another handler, called index handler, is auto-registered by the framework // if end developer does not managed to handle it by hand. IndexName string // PushTargets filenames (map's value) to // be served without additional client's requests (HTTP/2 Push) // when a specific request path (map's key WITHOUT prefix) // is requested and it's not a directory (it's an `IndexFile`). // // Example: // "/": { // "favicon.ico", // "js/main.js", // "css/main.css", // } PushTargets map[string][]string // PushTargetsRegexp like `PushTargets` but accepts regexp which // is compared against all files under a directory (recursively). // The `IndexName` should be set. // // Example: // "/": regexp.MustCompile("((.*).js|(.*).css|(.*).ico)$") // See `iris.MatchCommonAssets` too. PushTargetsRegexp map[string]*regexp.Regexp // Cache to enable in-memory cache and pre-compress files. Cache DirCacheOptions // When files should served under compression. Compress bool // List the files inside the current requested directory if `IndexName` not found. ShowList bool // If `ShowList` is true then this function will be used instead // of the default one to show the list of files of a current requested directory(dir). // See `DirListRich` package-level function too. DirList DirListFunc // Files downloaded and saved locally. Attachments Attachments // Optional validator that loops through each requested resource. AssetValidator func(ctx *context.Context, name string) bool }
详细了解文件服务器。
(adsbygoogle = window.adsbygoogle || []).push({});
从上下文中提供数据
SendFile(filename string, destinationName string) error SendFileWithRate(src, destName string, limit float64, burst int) error
Go 框架 iris 文档(二):https://developer.aliyun.com/article/1396603