摘要:請注意閉包的返回值必需是。開發(fā)者可以利用相關(guān)方法來自定義其內(nèi)容,會將閉包的返回值作為最終結(jié)果與其他后端服務(wù)的響應(yīng)合并,然后返回給訪問層。注意不要忘記本身是一個閉包否則,無法模擬過期后重新生成另一個的情況。
dgate:an API Gateway based on Vert.x
dgate是基于Vertx的API Gateway。運行dgate的命令如下:
java -jar dgate-version-fat.jar -Dconf=conf
其中的conf屬性用來指定運行所需的配置文件。
conf的文件格式在說明格式之前,先看一個例子:
apiGateway1 { port = 7000 login = "/login" urls { "/login" { required = ["sub", "password"] methods = [HttpMethod.GET, HttpMethod.POST] upstreamURLs = [ [ host: "localhost", port: 8080, url: "/login", after: { simpleResponse -> Map payload = [ sub: simpleResponse.payload.getString("sub"), name: simpleResponse.payload.getString("name"), role: simpleResponse.payload.getString("role") ] simpleResponse.payload.put("token", delegate.tokenGenerator.token(payload, 5)) simpleResponse } ] ] } "/summary" { expected { statusCode = 200 payload { eqLocations = [] opRateInLast30Days = [] myOrgs = [ ["name": "org1", "admin": false] ] } } } "/forward" { required = ["param1", "param2"] methods = ["GET", "POST"] upstreamURLs = [ [host: "localhost", port: 8080, url: "/test"] ] } "/composite" { required = ["param1", "param2"] methods = ["GET", "POST"] upstreamURLs = [ [host: "localhost", port: 8080, url: "/test1"], [host: "localhost", port: 8080, url: "/test2"] ] } } } apiGateway2 { port = 7001 host = "localhost" urls { "/mock" { expected { statusCode = 200 payload = [test: true] } } } }
dgate采用ConfigSlurper解析conf文件,因此其文件的語法實際上是Groovy語法。
conf文件由多個Api Gateway的定義組成,對于每個Gateway定義如下:
apiGatewayName { port //端口 host //綁定的ip或主機(jī)名,默認(rèn)0.0.0.0 login //后端login服務(wù)的配置 urls { URL配置(UrlConfig)列表 } //dgate暴露的url列表 }
對于每個URL配置,其結(jié)構(gòu)如下:
url { required //必需參數(shù)列表 methods //支持的HTTP Method upstreamURLs { 上游URL列表(UpStreamURL) } expected //期望返回值 }
其中:
required支持兩種格式:List和Map。前者適用于不區(qū)分HttpMethod時的參數(shù)驗證,后者則可以針對不同的HttpMethod分別進(jìn)行設(shè)置。
List,如:required = ["sub", "password"]
Map,如:required = [get: ["param1"], post: ["param2"], delete: ["param3"]]
expected和upStreamURLs兩個屬性不能并存
expected主要用于mock模式,其目的是為了便于依賴dgate的訪問層可以自行mock所需的響應(yīng),使得它們的開發(fā)進(jìn)度受dgate開發(fā)進(jìn)度的影響最小化。
對于expected的內(nèi)容:
statusCode和payload至少有一個
或針對具體的HTTP METHOD的返回值
對于每個上游URL,有3個屬性:host、port和url,其中url必需以"/"開始
不同類型的API Gateway請求API Gateway的目的是作為后端Service的一個統(tǒng)一集中點,簡化訪問層與后端Service的交互。說得更簡單點,其作用非常類似Facade。
因此,API Gateway的主要作用就是:
接受訪問層的請求
將請求轉(zhuǎn)發(fā)到對應(yīng)的后端服務(wù)
收集后端響應(yīng),統(tǒng)一組裝成response,然后返回給訪問層
從大的方面講,發(fā)給API Gateway的請求分成兩類:
轉(zhuǎn)發(fā)給一個上游URL,即上面的forward
轉(zhuǎn)發(fā)給多個上游URL,即上面的Composite
這便是為何upStreamURLs是一個列表的主要原因。對于每種請求:
forward
訪問層的request parameter直接轉(zhuǎn)發(fā)給后端service
后端service的response直接轉(zhuǎn)發(fā)給訪問層
composite
訪問層的request parameter會直接(并發(fā))轉(zhuǎn)發(fā)給每個后端服務(wù)
后端服務(wù)的response會merge在一起后再發(fā)給訪問層
對于每個發(fā)往后端的請求,dgate會采用Circuit Breaker來防護(hù),防止出現(xiàn)由于某個后端service的失效導(dǎo)致整個系統(tǒng)雪崩。同時,為了簡單起見,dgate和后端service之間只通過JSON進(jìn)行交互:
對于發(fā)往dgate的請求,dgate會將:request parameters、form變量、request body合并為一體,統(tǒng)一作為request body發(fā)往后端
對于后端響應(yīng),dgate只接受json格式
UpStreamURL的擴(kuò)展點如上節(jié)所說,API Gateway具備兩個職責(zé):轉(zhuǎn)發(fā)請求和轉(zhuǎn)發(fā)響應(yīng)。由于每個后端服務(wù)所需的request參數(shù)和產(chǎn)生的response不同,在這兩個階段,都需要對訪問層傳來的request和后端服務(wù)傳回的response進(jìn)行定制:
需要將訪問層的request適配成后端service所需的request,這就面臨著一些格式轉(zhuǎn)換,如參數(shù)改名、增減對應(yīng)的參數(shù)等。
需要對后端服務(wù)的response適配成訪問層所需的response,采用類似的格式轉(zhuǎn)換的動作。
針對這個需求,每個UpStreamURL都有兩個可選屬性可以利用。
before閉包upstreamURLs = [ [ host: "localhost", port: 8080, url: "/test", before: { params -> ... } ] ]
before閉包的參數(shù)為訪問層所發(fā)來的request parameters,其類型是一個JsonObject。開發(fā)者可以通過調(diào)用相關(guān)的方法來對其內(nèi)容進(jìn)行增減,dgate會將before閉包的返回值作為參數(shù)發(fā)給對應(yīng)的上游URL。故,在此處非常適合將多余的request params過濾掉。
請注意:before閉包的返回值必需是JsonObject。最簡單的before閉包如下:
before: { params -> params }after閉包
upstreamURLs = [ [ host: "localhost", port: 8080, url: "/test", after: { simpleResponse -> ... } ] ]
after閉包的參數(shù)為后端服務(wù)所發(fā)來的response,其類型是SimpleResponse。開發(fā)者可以利用相關(guān)方法來自定義其內(nèi)容,dgate會將after閉包的返回值作為最終結(jié)果與其他后端服務(wù)的響應(yīng)合并,然后返回給訪問層。故,此處適合對響應(yīng)進(jìn)行自定義。
請注意:after閉包的返回值必需是SimpleResponse。最簡單的after閉包如下:
after: { simpleResponse -> simpleResponse }給before/after閉包傳入工具類
由于Groovy閉包的特性,我們可以給before/after傳入工具類實例,供開發(fā)者使用。典型的例子如下:
"/login" { required = ["sub", "password"] methods = [HttpMethod.GET, HttpMethod.POST] upstreamURLs = [ [ host: "localhost", port: 8080, url: "/login", after: { simpleResponse -> simpleResponse.put(tokenGenerator.token(["sub": "13572209183", "name": "foxgem", "role": "normal"], 2)) simpleResponse } ] ] }
其中的tokenGenerator就是利用這個特性完成的,具體實現(xiàn)可以參見LoginHandler。注意,上述代碼中的2表示token的超時時間,單位為秒。
url path parametersUpStreamURL除了支持一般的url格式,還支持url path parameters,格式如下:
"/:x"
"/y/:x?"
"/:x?/test/:y?"
所有的參數(shù)以":"開始,以"?"結(jié)束的為可選參數(shù),規(guī)定如下:
當(dāng)url中有且僅有一個可選參數(shù)時,它必需為最后一個參數(shù)
當(dāng)url中有多個可選參數(shù)時,則只能從后向前不出現(xiàn)在url中,即:對于/:x?/:y?/:z?
/x/y/z,合法
/x/y,合法
/x,合法
/x/z,非法,它將解析對應(yīng)成:/x/y
Mock請求最簡單的mock請求的書寫如下:
"/mock" { expected { statusCode = 200 payload = [test: true] } }
若statusCode或payload本身是一個閉包,則dgate會將它們的返回值作為結(jié)果返回,這在excepted為一個動態(tài)值時非常有用,參見下面【Mock JWT Token】的例子。
上面的形式對于任何Http Method不加區(qū)分地返回同一個內(nèi)容。但在Restful URL中,往往會有一個URL要為不同的Http Method服務(wù),執(zhí)行不同動作(如CRUD),返回不同響應(yīng)體的情形。在dgate中可以以如下形式書寫:
"/mock" { expected { get { statusCode = 200 payload = [method: "get"] } post { statusCode = 200 payload = [method: "post"] } delete { statusCode = 200 payload = [method: "delete"] } } }
即對于每一種HTTP method,都有各自響應(yīng)體,每個響應(yīng)體的格式都是由statusCode和payload組成。
安全dgate支持JWT Token來認(rèn)證每個訪問層請求,當(dāng)配置中出現(xiàn)login時,安全機(jī)制即被觸發(fā)。
Login的配置若conf中沒有l(wèi)ogin配置,則所有url都是公共可訪問的。
若要對所有url都要求先登錄,則配置如下:
login = "/login"
若要忽略某些url,則配置如下:
login { url = "/login" ignore = [ 被忽略的url ] }
若只有部分url是需要訪問控制的,則配置如下:
login { url = "/login" only = [ 被控制的url ] }
注意:ignore和only不能同時存在。
JWT Tokendgate使用JWT Token來認(rèn)證每個訪問層請求,故每個請求必需先請求獲得jwt token,然后將每個token放入后續(xù)每個request的"Authorization"頭,這樣每個后續(xù)的request才會被認(rèn)為是有效請求,否則將返回401。
如何產(chǎn)生jwt token的職責(zé)由開發(fā)者來完成,它必需放入login配置部分,上面的例子給出了一個參考實現(xiàn)。
對于發(fā)往后端服務(wù)的每個請求,dgate會將前端請求Authorization頭中的jwt token附到請求的參數(shù)內(nèi),可以通過token來獲取,此時它已經(jīng)被解碼成一個JSON對象。
產(chǎn)生JWT Token的密鑰由下面的三個環(huán)境變量決定,故一旦配置中包含login,則需要在啟動dgate之前先設(shè)置這3個環(huán)境變量:
dgate_key_store,keystore文件路徑
dgate_key_type,keystore文件類型
dgate_key_password,keystore的密鑰,至少6位
下面是一個配置的例子
export dgate_key_store=./test1.jceks export dgate_key_type=jceks export dgate_key_password=test123
使用keytool來產(chǎn)生文件,例子如下:
keytool -genseckey -keystore test1.jceks -storetype jceks -storepass test123 -keyalg HMacSHA256 -keysize 2048 -alias HS256 -keypass test123
由于dgate利用Vert.x的JWTAuthProvider產(chǎn)生JWT Token,因此其密鑰文件為符合其要求的文件格式。關(guān)于密鑰和如何產(chǎn)生密鑰文件的命令,可以參見其文檔。
注意:
在產(chǎn)品環(huán)境中請安全地保管好這個密鑰文件!
在開發(fā)環(huán)境可以使用dgate自帶的測試密鑰文件:dgate,密碼為“dcloud”。請注意不要將其用于產(chǎn)品環(huán)境,否則為偽造證書提供了便利。
Mock JWT Token對于使用Mock功能來進(jìn)行開發(fā)的訪問層,有時會需要mock login來獲得mock的jwt token以便開發(fā)相應(yīng)的功能??梢詤⒖枷旅娴拇a:
import io.vertx.core.http.HttpMethod import io.vertx.core.Vertx import io.vertx.ext.auth.jwt.JWTAuth import top.dteam.dgate.utils.* apiGateway { port = 7000 login = "/login" urls { "/login" { required = ["sub", "password"] methods = [HttpMethod.GET, HttpMethod.POST] expected { statusCode = 200 payload = { JWTAuth jwtAuth = Utils.createAuthProvider(Vertx.vertx()) JWTTokenGenerator tokenGenerator = new JWTTokenGenerator(jwtAuth) [token: tokenGenerator.token(["sub": "13572209183", "name": "foxgem", "role": "normal"], 200)] } } } …… }
既然login指向的是dgate暴露的url,那么當(dāng)然也就是可以直接mock啦。
注意:不要忘記payload本身是一個閉包!否則,無法模擬JWT Token過期后重新生成另一個Token的情況。
刷新JWT Tokendgate支持JWT Token的刷新,刷新用的url為:/token-refresh。它會從Request Header中取出JWT,解碼,然后重新生成新的JWT。即,刷新JWT Token的前提是必須先獲得dgate的JWT Token。
刷新JWT Token的配置由login配置塊決定。當(dāng)login是一個url時,則使用缺省的刷新屬性。刷新屬性(單位:秒)包括:
refreshLimit,刷新時限,即對于一個超時的JWT Token,若距離當(dāng)前時間小于這個值,則允許刷新。否則返回401。
refreshExpire,新生成的JWT Token的時限,一旦超過,則對應(yīng)的JWT Token失效。
若要自定義這兩個值,則可按照如下定義:
login { …… refreshLimit = 30 * 60 refreshExpire = 30 * 60 …… }
若不指定,則使用缺省值。這兩個值的缺省值都為:30分鐘,即:30 * 60(秒)。
CORS支持對于某些情況下,需要打開CORS支持才能讓訪問層正常使用。在dgate中需要在apiGateway中添加如下的配置:
apiGateway { …… cors { allowedOriginPattern = "*" allowedMethods = [HttpMethod.GET, HttpMethod.POST, HttpMethod.DELETE] allowedHeaders = ["content-type"] allowCredentials = true } …… }
cors配置并非必需的,若沒有,dgate不會支持CORS。CORS的配置項目如下:
allowedOriginPattern,字符串,如 “http://localhost:7000”。
allowedHeaders,字符串集合,支持的HTTP請求HEADER集合
allowedMethods,Vertx的HttpMethod集合,支持的HTTP方法集合
exposedHeaders,字符串集合,允許暴露的響應(yīng)頭集合
maxAgeSeconds,整型,可用于緩存preflight的時間,單位(秒)
allowCredentials,是否允許Cookie
其中僅allowedOriginPattern是必填。但,對于提交格式為JSON的ajax請求,需要允許:"content-type"。
此外,在調(diào)試過程中,也可以注意瀏覽器給出的提示,根據(jù)相應(yīng)提示進(jìn)行配置。
警告:在產(chǎn)品環(huán)境中不要使用“*”作為allowedOriginPattern的值。
每個請求的附加參數(shù)dgate會給每個發(fā)往后端服務(wù)的請求參數(shù)中添加若干參數(shù),通過下面的key可以獲得:
nameOfApiGateway,Api Gateway的名字,字符串。
token,已解碼的jwt token,其類型是一個Map,內(nèi)容依賴于在產(chǎn)生token時設(shè)置的值。如:在產(chǎn)生時包含[sub, name, role]這幾個鍵值,則此處就獲得這3個鍵值。若在產(chǎn)生時為[sub, name, role, other],則此處就可以會有這4個鍵值。
注意:除了必需的幾個屬性,JWT Token中token本身是可以附加其他屬性進(jìn)來的。相當(dāng)于將token本身作為信息的載體。
斷路器設(shè)置dgate缺省會為每個上游服務(wù)(注:對于Mock服務(wù),斷路器設(shè)置無效)設(shè)置一個斷路器,缺省的配置如下:
最大失敗次數(shù)(maxFailures),3次
請求超時(timeout),5秒
斷路器重置時間(resetTimeout),10秒
若缺省的設(shè)置不合適,dgate支持兩個層次的設(shè)置:gateway級別和上游服務(wù)級別。并且,在兩者都存在時,上游服務(wù)的斷路器設(shè)置會覆蓋gateway級別的設(shè)置。
gateway級別的設(shè)置這個設(shè)置將對gateway內(nèi)所有的上游服務(wù)生效,例子如下:
apiGateway { …… circuitBreaker { maxFailures = 5 timeout = 10000 resetTimeout = 30000 } …… }上游服務(wù)級別的設(shè)置
這個設(shè)置僅對當(dāng)前上游服務(wù)生效,例子如下:
…… "/url" { upstreamURLs = [ [host: "localhost", port: 8080, url: "/test1", circuitBreaker: [maxFailures: 2, timeout: 3000, resetTimeout: 3000]] ] } ……
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/66564.html
摘要:最近,因為項目的需要,順手給它增加了一個新的特性。其中,對應(yīng)后端主動發(fā)起的推送,對于每一個推送地址,必填,單位為毫秒。,對應(yīng)后端接收前端消息的消費者。當(dāng)為閉包時,其返回值為結(jié)果。相關(guān)鏈接基于的輕量級上的的使用指南 由于簡單同時又強(qiáng)大的Mock特性,dgate在我的項目中除了作為簡單的API網(wǎng)關(guān),它也承擔(dān)著面向前端的Mock Server作用,保證前后端開發(fā)同步進(jìn)行。最近,因為項目的需要...
摘要:輕量級,部署簡單。此外,本文也不是入門文檔,而是為了預(yù)防陷坑而給出的指導(dǎo)意見,故在閱讀本文之前還請先仔細(xì)閱讀的文檔。可視作的一個最小部署和運行單元,簡單的說,可類比為。,主,負(fù)責(zé)部署程序中其他的。嚴(yán)格來講,之后,上述第一點并不完全正確。 一直以來早有將這些年用Vert.x的經(jīng)驗整理一下的想法,奈何天生不是勤快人,直到最近扶墻老師問起,遂成此文。 選擇理由 現(xiàn)在想想,我們應(yīng)該算是國內(nèi)用V...
摘要:對于集成測試,直接模擬實際的環(huán)境,再加上合適的,目前看來也還不錯。這里給出兩個例子集成測試單元測試都是基于寫的,各位可以體驗其酸爽度。好啦,本期內(nèi)容就此結(jié)束,請保持關(guān)注,期待下期繼續(xù)本系列其他文章入坑須知入坑須知 隨著Vert.x進(jìn)化到3.5.0,本系列也迎來了新篇章。 CORS的新變化 對于CORS,搞Web開發(fā)(不論你是前端,還是后端)的同志應(yīng)該不陌生,尤其是如今微服務(wù)盛行的時代,...
摘要:這一點其實是非常不妥的,有潛在的安全問題。這次,在項目中終于采用了以它為基礎(chǔ)的集群方案。相反,使用一個周期,但針對每個生成一個一次性的,模擬隨機(jī)發(fā)送。同時,要記得用完之后立即釋放。 當(dāng)初創(chuàng)建簡書賬號的時候曾立下宏愿,希望保持周更,無奈現(xiàn)實殘酷,整個5月都處于忙忙碌碌的狀態(tài),居然令這個本來并不算太宏偉的目標(biāo)難以為繼,最終導(dǎo)致5月份交了白卷!【好吧,我承認(rèn),是我意志不夠堅定,太懶了,;)】...
摘要:本教程是藍(lán)圖系列的第三篇教程,對應(yīng)的版本為。提供了一個服務(wù)發(fā)現(xiàn)模塊用于發(fā)布和獲取服務(wù)記錄。前端此微服務(wù)的前端部分,目前已整合至組件中。監(jiān)視儀表板用于監(jiān)視微服務(wù)系統(tǒng)的狀態(tài)以及日志統(tǒng)計數(shù)據(jù)的查看。而服務(wù)則負(fù)責(zé)發(fā)布其它服務(wù)如服務(wù)或消息源并且部署。 本文章是 Vert.x 藍(lán)圖系列 的第三篇教程。全系列: Vert.x Blueprint 系列教程(一) | 待辦事項服務(wù)開發(fā)教程 Vert....
閱讀 2138·2021-09-27 14:04
閱讀 1883·2019-08-30 15:55
閱讀 1707·2019-08-30 13:13
閱讀 1076·2019-08-30 13:07
閱讀 2754·2019-08-29 15:20
閱讀 3247·2019-08-29 12:42
閱讀 3345·2019-08-28 17:58
閱讀 3606·2019-08-28 17:56