iris框架是一款优秀的Go web服务器实现

Iris是Go语言的一个快速,简单但功能齐全且非常高效的Go Web框架。Iris为您的下一个网站或API提供了一个精美的表达和易于使用的基础,这些促使我将它的各种使用样例总结如下。下面的每个样例都是可以独立执行的一个web,参考官方文档写的,同时还添加了一些我们会用到的用例(比如第7,函数嵌套来实现登陆认证),用户只要copy到你的编辑器就可以执行运行,它仅仅依赖iris包。每个例子我都测试过,能正常运行,源码已经放到Github,地址在文章最下方。

前置准备
- 安装go运行时
- 下载iris包,go get -u github.com/kataras/iris

1. 快速开始一个iris网站
package main

import "github.com/kataras/iris"

func main() {
app := iris.Default()
app.Get("/ping", func(ctx iris.Context) {
ctx.JSON(iris.Map{
"message": "pong",
})
})
// listen and serve on http://0.0.0.0:8080.
app.Run(iris.Addr(":8080"))
}

2. query与post参数的用法,http://localhost:8080/post?id=1,page是个可选的参数,有默认值,name与message是post参数,可以用postman做测试
package main

import "github.com/kataras/iris"

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

app.Post("/post", func(ctx iris.Context) {
id := ctx.URLParam("id")
page := ctx.URLParamDefault("page", "0")
name := ctx.FormValue("name")
message := ctx.FormValue("message")
// or `ctx.PostValue` for POST, PUT & PATCH-only HTTP Methods.

app.Logger().Infof("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
})

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

3. 依赖注入,下面代码提供了三种依赖注入的方式
    package main

    import "github.com/kataras/iris"
    import "github.com/kataras/iris/hero"

    func main() {
        app := iris.Default()
        
        //1. Path Parameters - Built'n Dependencies
        helloHandler := hero.Handler(hello)
        app.Get("/builtin/{to:string}", helloHandler)

        //2. Services - Static Dependencies
        hero.Register(&myTestService{
            prefix: "Service: Hello",
        })
        helloServiceHandler := hero.Handler(helloService)
        app.Get("/service/{to:string}", helloServiceHandler)

        //3. Per-Request - Dynamic Dependencies
        hero.Register(func(ctx iris.Context) (form LoginForm) {
            ctx.ReadForm(&form)
            return
        })
        loginHandle := hero.Handler(login)
        app.Post("/dynamic/login", loginHandle)

        // listen and serve on http://0.0.0.0:8080.
        app.Run(iris.Addr(":8080"))
    }

    //1. Path Parameters - Built'n Dependencies
    func hello(to string) string {
        return "Hello " + to
    }

    //2. Services - Static Dependencies
    type Service interface {
        SayHello(to string) string
    }

    type myTestService struct {
        prefix string
    }

    func (s *myTestService) SayHello(to string) string {
        return s.prefix + " " + to
    }

    func helloService(to string, service Service) string {
        return service.SayHello(to)
    }

    //3. Per-Request - Dynamic Dependencies
    type LoginForm struct {
        Username string
        Password string
    }

    func login(form LoginForm) string {
        return "Hello " + form.Username
    }

4. 中间件,一个使用了iris框架的缓存中间件,一个是自定义的中间件
package main

import (
"github.com/kataras/iris"
"github.com/kataras/iris/hero"
"time"
"log"
)

const refreshEvery = 10 * time.Second

func main() {
app := iris.New()
app.Use(mymid)
app.Use(iris.Cache(refreshEvery))

helloHandler := hero.Handler(hello)
// Per route middleware, you can add as many as you desire.
app.Get("/builtin/{to:string}", helloHandler)

// Per route middleware, you can add as many as you desire.
app.Get("/benchmark", greet)

// Listen and serve on http://0.0.0.0:8080
app.Run(iris.Addr(":8080"))
}

func hello(to string) string {
log.Print("i am hello")
return "Hello " + to
}

func greet(ctx iris.Context) {
ctx.Header("X-Custom", "my custom header")
ctx.Writef("Hello World! %s", time.Now())
}

func mymid(ctx iris.Context) {
log.Print("i am mid")
ctx.Next()
}

5. 如何将一个处理器函数转换成一个中间件
package main

import (
"github.com/kataras/iris"
"net/http"
)

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

sillyHTTPHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
println(r.RequestURI)
})

sillyConvertedToIon := iris.FromStd(sillyHTTPHandler)
// FromStd can take (http.ResponseWriter, *http.Request, next http.Handler) too!
app.Use(sillyConvertedToIon)

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

6. 路径如何参数化,如何限制路径的值的取值范围,类型,长度等
package main

import "github.com/kataras/iris"

import (
"regexp"
)

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

// This handler will match /user/john but will not match neither /user/ or /user.
app.Get("/user/{name}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
ctx.Writef("Hello %s", name)
})

// This handler will match /users/42
// but will not match /users/-1 because uint should be bigger than zero
// neither /users or /users/.
app.Get("/users/{id:uint64}", func(ctx iris.Context) {
id := ctx.Params().GetUint64Default("id", 0)
ctx.Writef("User with ID: %d", id)
})

// len(name) <=255 otherwise this route will fire 404 Not Found
// and this handler will not be executed at all.
app.Get("/profile/{name:alphabetical max(255)}", func(ctx iris.Context){
name := ctx.Params().Get("name")
ctx.Writef("Hello %s", name)
})

latLonExpr := "^-?[0-9]{1,3}(?:\\.[0-9]{1,10})?$"
latLonRegex, _ := regexp.Compile(latLonExpr)

// Register your custom argument-less macro function to the :string param type.
// MatchString is a type of func(string) bool, so we use it as it is.
app.Macros().Get("string").RegisterFunc("coordinate", latLonRegex.MatchString)

app.Get("/coordinates/{lat:string coordinate()}/{lon:string coordinate()}", func(ctx iris.Context) {
ctx.Writef("Lat: %s | Lon: %s", ctx.Params().Get("lat"), ctx.Params().Get("lon"))
})

app.Macros().Get("string").RegisterFunc("range", func(minLength, maxLength int) func(string) bool {
return func(paramValue string) bool {
return len(paramValue) >= minLength && len(paramValue) <= maxLength
}
})
app.Get("/limitchar/{name:string range(1,200) else 400}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
ctx.Writef(`Hello %s | the name should be between 1 and 200 characters length
otherwise this handler will not be executed`, name)
})

app.Macros().Get("string").RegisterFunc("has", func(validNames []string) func(string) bool {
return func(paramValue string) bool {
for _, validName := range validNames {
if validName == paramValue {
return true
}
}
return false
}
})
app.Get("/static_validation/{name:string has([kataras,gerasimos,maropoulos])}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
ctx.Writef(`Hello %s | the name should be "kataras" or "gerasimos" or "maropoulos"
otherwise this handler will not be executed`, name)
})

// However, this one will match /user/john/send and also /user/john/everything/else/here
// but will not match /user/john neither /user/john/.
app.Post("/user/{name:string}/{action:path}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
action := ctx.Params().Get("action")
message := name + " is " + action
ctx.WriteString(message)
})

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

7. 使用函数嵌套实现统计处理事务,比如写日志,登陆认证等
package main

import "github.com/kataras/iris"
import "github.com/kataras/iris/context"
import "net/http"
import "log"

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", basicAuth(sayHello))
app.Get("/welcome2", sayHello)

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

func sayHello(ctx iris.Context) {
firstname := ctx.URLParamDefault("firstname", "Guest")
// shortcut for ctx.Request().URL.Query().Get("lastname").
lastname := ctx.URLParam("lastname")

ctx.Writef("Hello %s %s", firstname, lastname)
}

func basicAuth(h context.Handler) context.Handler {
return func(ctx iris.Context) {
if 1 == 2 {
log.Print("yes")
h(ctx)
} else {
log.Print("no")
http.Error(ctx.ResponseWriter(), http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
}
}

8. 文件上传,这个没有做上传的页面,用户需要用postman之类的工具测试,或者自己做个表单页面也行
package main

import (
"mime/multipart"
"strings"

"github.com/kataras/iris"
)

const maxSize = 5 << 20 // 5MB

func main() {
app := iris.Default()
app.Post("/upload", iris.LimitRequestBodySize(maxSize), func(ctx iris.Context) {
//
// UploadFormFiles
// uploads any number of incoming files ("multiple" property on the form input).
//

// The second, optional, argument
// can be used to change a file's name based on the request,
// at this example we will showcase how to use it
// by prefixing the uploaded file with the current user's ip.
ctx.UploadFormFiles("./uploads", beforeSave)
})

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

func beforeSave(ctx iris.Context, file *multipart.FileHeader) {
ip := ctx.RemoteAddr()
// make sure you format the ip in a way
// that can be used for a file name (simple case):
ip = strings.Replace(ip, ".", "_", -1)
ip = strings.Replace(ip, ":", "_", -1)

// you can use the time.Now, to prefix or suffix the files
// based on the current time as well, as an exercise.
// i.e unixTime :=  time.Now().Unix()
// prefix the Filename with the $IP-
// no need for more actions, internal uploader will use this
// name to save the file into the "./uploads" folder.
file.Filename = ip + "-" + file.Filename
}

9. 写日志,这里是将日志写入磁盘,安装每天一个文件存储
package main

import (
"os"
"time"

"github.com/kataras/iris"
)

// Get a filename based on the date, just for the sugar.
func todayFilename() string {
today := time.Now().Format("20060102")
return today + ".log"
}

func newLogFile() *os.File {
filename := todayFilename()
// Open the file, this will append to the today's file if server restarted.
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}

return f
}

func main() {
f := newLogFile()
defer f.Close()

app := iris.New()
// Attach the file as logger, remember, iris' app logger is just an io.Writer.
// Use the following code if you need to write the logs to file and console at the same time.
// app.Logger().SetOutput(io.MultiWriter(f, os.Stdout))
app.Logger().SetOutput(f)

app.Get("/ping", func(ctx iris.Context) {
// for the sake of simplicity, in order see the logs at the ./_today_.txt
ctx.Application().Logger().Infof("Request path: %s", ctx.Path())
ctx.WriteString("pong")
})

// Navigate to http://localhost:8080/ping
// and open the ./logs{TODAY}.txt file.
app.Run(
iris.Addr(":8080"),
iris.WithoutBanner,
iris.WithoutServerError(iris.ErrServerClosed),
)
}

总结:iris web 框架,到这里就基本上把我们写一个网站要用到的功能点都杭盖到了,入门非常简单,也非常的优雅,它有其他语言的痕迹,又独辟蹊径的语法,让人爱不释手的好框架。

Github源码:https://github.com/iissy/goirisexamples
Posted by 何敏
on 2019/01/13 23:29:45
Copyright ©2018 程序员网址导航 粤ICP备14091834号