在上篇文章介绍routing时有提到Party
时有传入一个handler
不知道读者们有没有注意到,所以今天来介绍那个middleware
。
本文同步放置於此
其实middleware在很多网页程序里都有,不过在介绍iris的middleware之前还是介绍一下什麽是middleware,所以接下来的内容就先介绍什麽是middleware,再来再开始介绍在iris怎麽撰写middleware。
什麽是middleware呢,这里还是先看看middleware wiki的解释吧,对於笔者的解释与其类似,简单来说明就是在网页程序的生命周期中切入一段服务,藉此来处理所有的请求,接下来就开始跟大家介绍如何撰写iris的middleware。
这边利用iris-go custom-middleware来说明如何撰写middleware,请大家先看看以下例子
func Logger() iris.Handler {
return func(ctx iris.Context) {
t := time.Now()
// Set a shared variable between handlers
ctx.Values().Set("framework", "iris")
// before request
ctx.Next()
// after request
latency := time.Since(t)
log.Print(latency)
// access the status we are sending
status := ctx.GetStatusCode()
log.Println(status)
}
}
func main() {
app := iris.New()
app.Use(Logger())
app.Get("/test", func(ctx iris.Context) {
// retrieve a value set by the middleware.
framework := ctx.Values().GetString("framework")
// it would print: "iris"
log.Println(framework)
})
app.Listen(":8080")
}
简单讲如何撰写一个自订义的middleware就是返还一个handdler
,撰写middleware的要点主要是区分处理请求之前跟处理完请求的部分,看到上面的例子就知道其中的区隔是一个ctx.Next()
,呼叫这个方法之前是处理请求之前,呼叫完就是处理请求之後。
然而如何分享变数在handler
之间呢,就是透过ctx.Values().Set(key string, value object)
与ctx.Values().GetString(key string) string
之类的方法。
上面例子说明如何撰写middleware,也提到一个如何使用middleware的方法,简单来说就是透过app.Use(h handler)来使用middleware,不过使用的方式不只这样,还有下列几种方法
至於其中的差别可以看看iris-go middleware的内容,首先先看看他的例子
package main
import (
"net/http"
"github.com/kataras/iris/v12"
)
func main() {
app := iris.New()
app.WrapRouter(routerWrapper)
app.UseRouter(routerMiddleware)
app.UseGlobal(globalMiddleware)
app.Use(useMiddleware)
app.UseError(errorMiddleware)
// app.Done(done)
// app.DoneGlobal(doneGlobal)
// Adding a OnErrorCode(iris.StatusNotFound) causes `.UseGlobal`
// to be fired on 404 pages without this,
// only `UseError` will be called, and thus should
// be used for error pages.
app.OnErrorCode(iris.StatusNotFound, notFoundHandler)
app.Get("/", mainHandler)
app.Listen(":8080")
}
func mainHandler(ctx iris.Context) {
ctx.WriteString("Main Handler")
}
func notFoundHandler(ctx iris.Context) {
ctx.WriteString("404 Error Handler")
}
上面是主程序以及绑定middleware的资讯,接下来看看期middleware的内容
func routerWrapper(w http.ResponseWriter, r *http.Request,
router http.HandlerFunc) {
if r.URL.Path == "/" {
w.Write([]byte("#1 .WrapRouter\n"))
/* Note for new Gophers:
If we Write anything here on an error resource in the raw
`net/http` wrapper like this one, then the response writer will
automatically send a `200` OK status code (when we first write).
Any error handler executed after this will not fire as expected.
Also, when `w.WriteHeader` is called you can NOT change the
status code later on.
In Iris Handlers, if you write before the status code has been
set, then it will also automatically send the 200 OK status
code which then cannot be changed later. However, if we call
`ctx.StatusCode` inside an Iris Handler without writing any
content, then we can change the status code later on. When you
need to change that behaviour, you must start the handler with
a `ctx.Record` call.
*/
}
// Continue by executing the Iris Router and let it do its job.
router(w, r)
}
func routerMiddleware(ctx iris.Context) {
if ctx.Path() == "/" {
ctx.WriteString("#2 .UseRouter\n")
// The same caveat described in routerWrapper applies here as well.
}
ctx.Next()
}
func globalMiddleware(ctx iris.Context) {
ctx.WriteString("#3 .UseGlobal\n")
ctx.Next()
}
func useMiddleware(ctx iris.Context) {
ctx.WriteString("#4 .Use\n")
ctx.Next()
}
func errorMiddleware(ctx iris.Context) {
ctx.WriteString("#3 .UseError\n")
ctx.Next()
}
这里的middleware都只是写log而已,然後执行这个程序会有甚麽结果呢,请大家看看以下的内容
#1 .WrapRouter
#2 .UseRouter
#3 .UseGlobal
#4 .Use
Main Handler
由上面例子可以知道,注册middleware的执行顺序是如上面显示的顺序WrapRouter
最先被执行、Use
最後,接下来才执行绑定的handler
,除此之外如果触发404会有下列的输出
#3 .UseGlobal
#3 .UseError
404 Error Handler
不过这里有一个部分需要注意的,就是如果OnErrorCode
没有绑定到的状态被触发,UseGlobal
也不会被触发,例如触发的不是404而是400则会输出的log如下
#3 .UseError
Not Found
最後跟大家说明如何修改原来的middleware,简单说就是像接水管一样,再接原来的middleware之前先接另外一个middleware去判断後即可,大家可以看看下列例子
package main
import (
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/middleware/basicauth"
)
func main() {
users := map[string]string{"username":"password"}
auth := basicauth.New(basicauth.Default(users))
app.UseRouter(skipStaticSubdomain(auth)) // <--
// [...]
app.Listen(":80")
}
func skipStaticSubdomain(handler iris.Handler) iris.Handler {
return func(ctx iris.Context) {
if ctx.Subdomain() == "static." {
// continue to the next or main handler and exit.
ctx.Next()
return
}
handler(ctx)
}
}
除了上述的例子之外,另外可以把condition
跟handler
分开来写,透过iris.NewConditionalHandler(filter Filter, handlers ...Handler) Handler
来改写middleware,详见下列例子
app.UseRouter(iris.NewConditionalHandler(isNotStaticSubdomain, auth))
func isNotStaticSubdomain(ctx iris.Context) bool {
return ctx.Subdomain() != "static."
}
本篇介绍什麽是middleware,并且介绍如何在iris撰写middleware,希望大家对於iris的middleware有初步的概念。
环境 Windows 10 21H1 Visual Studio 2019 前情提要 在【Day 0...
功能分解对应於各种功能关系,如原始复杂业务功能的开发方式。它主要关注如何开发整体功能及其各个组件之间...
建立资料表:CREATE TABLE 说明: 建立资料表之前,首先必须拥有DBA授权的CREATE ...
今天来直接上手开始我们的 Google Apps Script 之旅啦! 我们在使用 Google ...
接续上一篇 这次要讲的是我研究中途试过的另一个方法 Substituting 这其实是我一开始的想法...