日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
創(chuàng)新互聯(lián)GoFrame教程:GoFrame路由管理-中間件/攔截器

?GOFrame?提供了優(yōu)雅的中間件請求控制方式,該方式也是主流的?WebServer?提供的請求流程控制方式,基于中間件設(shè)計(jì)可以為?WebServer?提供更靈活強(qiáng)大的插件機(jī)制。經(jīng)典的中間件洋蔥模型:

站在用戶的角度思考問題,與客戶深入溝通,找到望江網(wǎng)站設(shè)計(jì)與望江網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、主機(jī)域名、虛擬主機(jī)、企業(yè)郵箱。業(yè)務(wù)覆蓋望江地區(qū)。

中間件定義

中間件的定義和普通HTTP執(zhí)行方法?HandlerFunc?一樣,但是可以在?Request?參數(shù)中使用?Middleware?屬性對象來控制請求流程。

我們拿一個(gè)跨域請求的中間件定義來示例說明一下:

func MiddlewareCORS(r *ghttp.Request) {
	r.Response.CORSDefault()
	r.Middleware.Next()
}

可以看到在該中間件中執(zhí)行完成跨域請求處理的邏輯后,使用?r.Middleware.Next()?方法進(jìn)一步執(zhí)行下一個(gè)流程;如果這個(gè)時(shí)候直接退出不調(diào)用?r.Middleware.Next()?方法的話,將會(huì)退出后續(xù)的執(zhí)行流程(例如可以用于請求的鑒權(quán)處理)。

中間件類型

中間件的類型分為兩種:前置中間件和后置中間件。前置即在路由服務(wù)函數(shù)調(diào)用之前調(diào)用,后置即在其后調(diào)用。

前置中間件

其定義類似于:

func Middleware(r *ghttp.Request) {
	// 中間件處理邏輯
	r.Middleware.Next()
}

后置中間件

其定義類似于:

func Middleware(r *ghttp.Request) {
	r.Middleware.Next()
	// 中間件處理邏輯
}

中間件注冊

中間件的注冊有多種方式,參考接口文檔: https://pkg.go.dev/github.com/gogf/gf/v2/net/ghttp

全局中間件

func (s *Server) Use(handlers ...HandlerFunc)

全局中間件是可以獨(dú)立使用的請求攔截方法,通過路由規(guī)則的方式進(jìn)行注冊,綁定到?Server?上,由于中間件需要執(zhí)行請求攔截操作,因此往往是使用"模糊匹配"或者"命名匹配"規(guī)則。

全局中間件僅對動(dòng)態(tài)請求攔截有效,無法攔截靜態(tài)文件請求。

分組路由中間件

func (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup

分組路由中注冊的中間件綁定到當(dāng)前分組路由中的所有的服務(wù)請求上,當(dāng)服務(wù)請求被執(zhí)行前會(huì)調(diào)用到其綁定的中間件方法。 分組路由僅有一個(gè)?Middleware?的中間件注冊方法。分組路由中間件與全局中間件不同之處在于,分組路由中間件無法獨(dú)立使用,必須在分組路由注冊中使用,并且綁定到當(dāng)前分組路由中所有的路由上作為路由方法的一部分。

執(zhí)行優(yōu)先級

全局中間件

由于全局中間件也是通過路由規(guī)則執(zhí)行,那么也會(huì)存在執(zhí)行優(yōu)先級:

  1. 首先,由于全局中間件是基于模糊路由匹配,因此當(dāng)同一個(gè)路由匹配到多個(gè)中間件時(shí),會(huì)按照路由的深度優(yōu)先規(guī)則執(zhí)行,具體請查看路由章節(jié);
  2. 其次,同一個(gè)路由規(guī)則下,會(huì)按照中間件的注冊先后順序執(zhí)行,中間件的注冊方法也支持同時(shí)按照先后順序注冊多個(gè)中間件;
  3. 最后,為避免優(yōu)先級混淆和后續(xù)管理,建議將所有中間件放到同一個(gè)地方進(jìn)行先后順序注冊來控制執(zhí)行優(yōu)先級;

這里的建議來參考于?gRPC?的攔截器設(shè)計(jì),沒有過多的路由控制,僅在一個(gè)地方同一個(gè)方法統(tǒng)一注冊。往往越簡單,越容易理解,也便于長期維護(hù)。

分組路由中間件

分組路由中間件是綁定到分組路由上的服務(wù)方法,不存在路由規(guī)則匹配,因此只會(huì)按照注冊的先后順序執(zhí)行。

中間件示例

示例1,允許跨域請求

第一個(gè)例子,也是比較常見的功能需求。

我們需要在所有API請求之前增加允許跨域請求的返回?Header?信息,該功能可以通過中間件實(shí)現(xiàn):

package main

import (
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

func MiddlewareCORS(r *ghttp.Request) {
	r.Response.CORSDefault()
	r.Middleware.Next()
}

func main() {
	s := g.Server()
	s.Group("/api.v2", func(group *ghttp.RouterGroup) {
		group.Middleware(MiddlewareCORS)
		group.ALL("/user/list", func(r *ghttp.Request) {
			r.Response.Writeln("list")
		})
	})
	s.SetPort(8199)
	s.Run()
}

執(zhí)行后,終端打印出路由表信息如下:

SERVER  | DOMAIN  | ADDRESS | METHOD |       ROUTE       |      HANDLER      |     MIDDLEWARE
|---------|---------|---------|--------|-------------------|-------------------|---------------------|
  default | default | :8199   | ALL    | /api.v2/user/list | main.main.func1.1 | main.MiddlewareCORS
|---------|---------|---------|--------|-------------------|-------------------|---------------------|

這里我們使用?group.Middleware(MiddlewareCORS)?將跨域中間件通過分組路由的形式注冊綁定到了?/api.v2?路由下所有的服務(wù)函數(shù)中。隨后我們可以通過請求 http://127.0.0.1:8199/api.v2/user/list 來查看允許跨域請求的?Header?信息是否有返回。

示例2,請求鑒權(quán)處理

我們在跨域請求中間件的基礎(chǔ)之上加上鑒權(quán)中間件。

為了簡化示例,在該示例中,當(dāng)請求帶有?token?參數(shù),并且參數(shù)值為?123456?時(shí)可以通過鑒權(quán),并且允許跨域請求,執(zhí)行請求方法;否則返回?403 Forbidden?狀態(tài)碼。

package main

import (
	"net/http"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

func MiddlewareAuth(r *ghttp.Request) {
	token := r.Get("token")
	if token.String() == "123456" {
		r.Response.Writeln("auth")
		r.Middleware.Next()
	} else {
		r.Response.WriteStatus(http.StatusForbidden)
	}
}

func MiddlewareCORS(r *ghttp.Request) {
	r.Response.Writeln("cors")
	r.Response.CORSDefault()
	r.Middleware.Next()
}

func main() {
	s := g.Server()
	s.Group("/api.v2", func(group *ghttp.RouterGroup) {
		group.Middleware(MiddlewareCORS, MiddlewareAuth)
		group.ALL("/user/list", func(r *ghttp.Request) {
			r.Response.Writeln("list")
		})
	})
	s.SetPort(8199)
	s.Run()
}

執(zhí)行后,終端打印出路由表信息如下:

SERVER  | DOMAIN  | ADDRESS | METHOD |       ROUTE       |      HANDLER      |               MIDDLEWARE
|---------|---------|---------|--------|-------------------|-------------------|-----------------------------------------|
  default | default | :8199   | ALL    | /api.v2/user/list | main.main.func1.1 | main.MiddlewareCORS,main.MiddlewareAuth
|---------|---------|---------|--------|-------------------|-------------------|-----------------------------------------|

可以看到,我們的服務(wù)方法綁定了兩個(gè)中間件,跨域中間件和而鑒權(quán)中間件。 請求時(shí)將會(huì)按照中間件注冊的先后順序,先執(zhí)行?MiddlewareCORS?全局中間件,再執(zhí)行?MiddlewareAuth?分組中間件。 隨后我們可以通過請求 http://127.0.0.1:8199/api.v2/user/list 和  http://127.0.0.1:8199/api.v2/user/list?token=123456 對比來查看效果。

示例3,鑒權(quán)例外處理

使用分組路由中間件可以很方便地添加鑒權(quán)例外,因?yàn)橹挥挟?dāng)前分組路由下注冊的服務(wù)方法才會(huì)綁定并執(zhí)行鑒權(quán)中間件,否則并不會(huì)執(zhí)行到鑒權(quán)中間件。

package main

import (
	"net/http"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

func MiddlewareAuth(r *ghttp.Request) {
	token := r.Get("token")
	if token.String() == "123456" {
		r.Middleware.Next()
	} else {
		r.Response.WriteStatus(http.StatusForbidden)
	}
}

func main() {
	s := g.Server()
	s.Group("/admin", func(group *ghttp.RouterGroup) {
		group.ALL("/login", func(r *ghttp.Request) {
			r.Response.Writeln("login")
		})
		group.Group("/", func(group *ghttp.RouterGroup) {
			group.Middleware(MiddlewareAuth)
			group.ALL("/dashboard", func(r *ghttp.Request) {
				r.Response.Writeln("dashboard")
			})
		})
	})
	s.SetPort(8199)
	s.Run()
}

執(zhí)行后,終端打印出路由表信息如下:

SERVER  | ADDRESS | DOMAIN  | METHOD | P |      ROUTE       |       HANDLER       |     MIDDLEWARE
|---------|---------|---------|--------|---|------------------|---------------------|---------------------|
  default |  :8199  | default |  ALL   | 2 | /admin/dashboard | main.main.func1.2.1 | main.MiddlewareAuth
|---------|---------|---------|--------|---|------------------|---------------------|---------------------|
  default |  :8199  | default |  ALL   | 2 | /admin/login     | main.main.func1.1   |
|---------|---------|---------|--------|---|------------------|---------------------|---------------------|

可以看到,只有?/admin/dashboard?路由的服務(wù)方法綁定了鑒權(quán)中間件?main.MiddlewareAuth?,而?/admin/login?路由的服務(wù)方法并沒有添加鑒權(quán)處理。 隨后我們訪問以下URL查看效果: 

  1. http://127.0.0.1:8199/admin/login
  2. http://127.0.0.1:8199/admin/dashboard
  3. http://127.0.0.1:8199/admin/dashboard?token=123456

示例4,統(tǒng)一的錯(cuò)誤處理

基于中間件,我們可以在服務(wù)函數(shù)執(zhí)行完成后做一些后置判斷的工作,特別是統(tǒng)一數(shù)據(jù)格式返回、結(jié)果處理、錯(cuò)誤判斷等等。這種需求我們可以使用后置的中間件類型來實(shí)現(xiàn)。我們使用一個(gè)簡單的例子,用來演示如何使用中間件對所有的接口請求做后置判斷處理,作為一個(gè)拋磚引玉作用。

package main

import (
	"net/http"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

func MiddlewareAuth(r *ghttp.Request) {
	token := r.Get("token")
	if token.String() == "123456" {
		r.Middleware.Next()
	} else {
		r.Response.WriteStatus(http.StatusForbidden)
	}
}

func MiddlewareCORS(r *ghttp.Request) {
	r.Response.CORSDefault()
	r.Middleware.Next()
}

func MiddlewareErrorHandler(r *ghttp.Request) {
	r.Middleware.Next()
	if r.Response.Status >= http.StatusInternalServerError {
		r.Response.ClearBuffer()
		r.Response.Writeln("哎喲我去,服務(wù)器居然開小差了,請稍后再試吧!")
	}
}

func main() {
	s := g.Server()
	s.Use(MiddlewareCORS)
	s.Group("/api.v2", func(group *ghttp.RouterGroup) {
		group.Middleware(MiddlewareAuth, MiddlewareErrorHandler)
		group.ALL("/user/list", func(r *ghttp.Request) {
			panic("db error: sql is xxxxxxx")
		})
	})
	s.SetPort(8199)
	s.Run()
}

執(zhí)行后,終端打印出路由表信息如下:

SERVER  | DOMAIN  | ADDRESS | METHOD |       ROUTE       |       HANDLER       |                   MIDDLEWARE
|---------|---------|---------|--------|-------------------|---------------------|-------------------------------------------------|
  default | default | :8199   | ALL    | /*                | main.MiddlewareCORS | GLOBAL MIDDLEWARE
|---------|---------|---------|--------|-------------------|---------------------|-------------------------------------------------|
  default | default | :8199   | ALL    | /api.v2/user/list | main.main.func1.1   | main.MiddlewareAuth,main.MiddlewareErrorHandler
|---------|---------|---------|--------|-------------------|---------------------|-------------------------------------------------|

在該示例中,我們在后置中間件中判斷有無系統(tǒng)錯(cuò)誤,如果有則返回固定的提示信息,而不是把敏感的報(bào)錯(cuò)信息展示給用戶。當(dāng)然,在真實(shí)的項(xiàng)目場景中,往往還有是需要解析返回緩沖區(qū)的數(shù)據(jù),例如?JSON?數(shù)據(jù),根據(jù)當(dāng)前的執(zhí)行結(jié)果進(jìn)行封裝返回固定的數(shù)據(jù)格式等等。

執(zhí)行該示例后,訪問 http://127.0.0.1:8199/api.v2/user/list?token=123456 查看效果。

示例5,自定義日志處理

我們來更進(jìn)一步完善一下以上示例,我們將請求日志包括狀態(tài)碼輸出到終端。這里我們必須得使用”全局中間件”了,這樣可以攔截處理到所有的服務(wù)請求,甚至?404?請求。

package main

import (
	"net/http"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

func MiddlewareAuth(r *ghttp.Request) {
	token := r.Get("token")
	if token.String() == "123456" {
		r.Middleware.Next()
	} else {
		r.Response.WriteStatus(http.StatusForbidden)
	}
}

func MiddlewareCORS(r *ghttp.Request) {
	r.Response.CORSDefault()
	r.Middleware.Next()
}

func MiddlewareLog(r *ghttp.Request) {
	r.Middleware.Next()
	errStr := ""
	if err := r.GetError(); err != nil {
		errStr = err.Error()
	}
	g.Log().Println(r.Response.Status, r.URL.Path, errStr)
}

func main() {
	s := g.Server()
	s.SetConfigWithMap(g.Map{
		"AccessLogEnabled": false,
		"ErrorLogEnabled":  false,
	})
	s.Use(MiddlewareLog, MiddlewareCORS)
	s.Group("/api.v2", func(group *ghttp.RouterGroup) {
		group.Middleware(MiddlewareAuth)
		group.ALL("/user/list", func(r *ghttp.Request) {
			panic("??!我出錯(cuò)了!")
		})
	})
	s.SetPort(8199)
	s.Run()
}

可以看到,我們注冊了一個(gè)全局的日志處理中間件以及跨域中間件,而鑒權(quán)中間件是注冊到?/api.v2?路由下。

執(zhí)行后,我們可以通過請求 http://127.0.0.1:8199/api.v2/user/list 和 http://127.0.0.1:8199/api.v2/user/list?token=123456 對比來查看效果,并查看終端的日志輸出情況。


當(dāng)前題目:創(chuàng)新互聯(lián)GoFrame教程:GoFrame路由管理-中間件/攔截器
文章來源:http://www.5511xx.com/article/dhssese.html