序文
Zuulは、Netflixが提供するオープンソースのコンポーネントであり、クラウドプラットフォームで動的なルーティング、監視、回復力、セキュリティ、その他のエッジサービスを提供することを約束します。また、ゲートウェイの重要な部分として使用する多くの企業もあります。今年、同社のアーキテクチャグループは、ゲートウェイ製品の開発、動的ルーティング、動的権限、現在の制限クォータ、およびその他の機能を統合し、他の部門のプロジェクトに統一された外部ネットワークコール管理を提供し、最終的に製品の形成を提供することを決定しました(ALIは実際にこの点で成熟したゲートウェイ製品を持っていますが、パーソナライズされた構成には適していません。
この記事では、主にSpring Cloud Zuul Unified Exception HandlingとFallbackに関する関連コンテンツを紹介します。参照と学習のために共有されます。以下ではあまり言いません。詳細な紹介を一緒に見てみましょう。
1。フィルターでの統一例外処理
実際、SpringCloudのEDGware SR2バージョンでは、ZuFilterのエラーの統一処理がありますが、実際の開発では、各チームにはエラーの応答方法のための独自の処理仕様があると思います。では、カスタム例外処理を行うにはどうすればよいですか?
最初にSpringCloudが提供するSenderrorfilterを参照できます。
/ * * Copyright 2013-2015元の著者または著者。 * * Apacheライセンス、バージョン2.0(「ライセンス」)に基づいてライセンスされています。 *ライセンスに準拠している場合を除き、このファイルを使用することはできません。 *ライセンスのコピーを取得することができます * * http://www.apache.org/licenses/license-2.0 * *該当する法律で要求されていない場合、または書面で合意しない限り、ライセンスに基づいて配布されるソフトウェア *は、保証または条件なしで「現状」に分配されます。 *権限を管理する特定の言語のライセンスと、ライセンスに基づく制限を参照してください。 */package org.springframework.cloud.netflix.zuul.filters.post;import javax.servlet.RequestDispatcher;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.logging.Log;import org.apache.commons.logging.logfactory; Import org.springframework.beans.factory.annotation.value; import org.springframework.cloud.netflix.zuul.util.zuulruntimeexcection; Import org.springframework.util.refletionutiluss; org.springframework.util.stringutils; Import com.netflix.zuul.zuulfilter; import com.netflix.zuul.context.requestContext; import com.netflix.zuul.exception.zuulexception; Import static springframework.cloud.netflix.zuul.filters.support.filterconstants.error_type; Import static org.springframework.cloud.netflix.zuul.filters.support.filterconstants.send_eror_filter_order_order_order_order_order_order_order_ord to /error(デフォルトで){@link requestContext#getThrowable()}がnullではありません。 * * @author spencer gibb * /// dodo:edgwarepublicクラスでエラーパッケージに移動しますsenderrorfilter拡張zuflilter {private static final log = logefactory.getlog(senderrorfilter.class);保護された静的な最終文字列send_error_filter_ran = "senderrorfilter.ran"; @value( "$ {error.path:/error}")private string errerpath; @Override public String filterType(){return error_type; } @Override public int filterorder(){return send_error_filter_order; } @Override public boolean sextfilter(){requestContext ctx = requestContext.getCurrentContext(); // ctx.getThrowable()!= null &&!ctx.getboolean(send_error_filter_ran、false、false); } @Override public object run(){try {requestContext ctx = requestContext.getCurrentContext(); zuulexception例外= findzuulexception(ctx.getThrowable()); httpservletrequest request = ctx.getRequest(); request.setattribute( "javax.servlet.error.status_code"、exception.nstatuscode); log.warn( "フィルタリング中のエラー"、例外); request.setattribute( "javax.servlet.error.exception"、例外); if(stringutils.hastext(exception.errorcause)){request.setattribute( "javax.servlet.error.message"、Exception.errorcause); } requestdispatcher dispatcher = request.getRequestDispatcher(this.ErrorPath); if(dispatcher!= null){ctx.set(send_error_filter_ran、true); if(!ctx.getResponse()。isCommitted()){ctx.setResponsestatusCode(exception.nstatuscode); dispatcher.forward(request、ctx.getResponse()); }}} catch(Exception ex){ReflectionUtils.RethRowRuntimeException(ex); } nullを返します。 } zuulexception findzuulexception(スロー可能なスロー可能){if(throwable.getCause()zuulruntimeexceptionのインスタンス){//これは、ローカルフィルターリターン(zuulexception)の1つが開始された障害であるthrow.getcause(); getCause(); } if(throwable.getCause()instanceof zuulexception){// wrapped zuul exception return(zuulexception)throwable.getCause(); } if(Zuulexceptionのスロー可能なインスタンス){// Zuul Lifecycle Return(Zuulexception)によってスローされた例外。 } //フォールバック、ここに到達してはいけませんnew Zuulexception(Throwable、httpservletresponse.sc_internal_server_error、null); } public void setErrorpath(String ErrorPath){this.ErrorPath = errorPath; }}ここでは、いくつかの重要なポイントを見つけることができます。
1)上記のコードでは、フィルターが関連するエラー情報をリクエストに入れていることがわかります。
request.setattribute( "javax.servlet.error.status_code"、exception.nstatuscode);
request.setattribute( "javax.servlet.error.exception"、例外);
request.setattribute( "javax.servlet.error.message"、Exception.errorcause);
2)エラーが処理された後、処理のためにXXX/エラーアドレスに転送されます
その後、実験を行うことができます。ゲートウェイサービスプロジェクトモジュールに例外をスローするフィルターを作成します。
パッケージcom.hzgj.lyrk.springcloud.gateway.server.filter; Import com.netflix.zuul.zuulfilter; Import lombok.extern.slf4j.slf4j; Import org.springframework.stereototy.component; public string filterType(){return "post"; } @Override public int filterOrder(){return 9; } @Override public boolean sefsfilter(){return true; } @Override public Object run(){log.info( "run error test ...");新しいruntimeexception()を投げる; // nullを返します。 }}次に、エラーを処理するコントローラーを定義します。
パッケージcom.hzgj.lyrk.springcloud.gateway.server.filter; Import org.springframework.http.httpstatus; Import org.springframework.http.responseentity; Import org.springframework.web.bind.annotation. org.springframework.web.bind.annotation.restController; Import javax.servlet.http.httpservletrequest; @restcontrollerpublic class errorhandler {@getmapping(value = "/error")Public Responsementity <errorbean>エラーrequest.getAttribute( "javax.servlet.error.message")。toString(); errorbean errorbean = new errorbean(); errorbean.setMessage(メッセージ); errorbean.setReason( "プログラムエラー");新しいresponseNtityを返します<>(errorbean、httpstatus.bad_gateway); } private static class errorbean {private string message;プライベートストリングの理由; public string getMessage(){return message; } public void setMessage(string message){this.message = message; } public string getReason(){return理由; } public void setReason(String reason){this.Reason = Reason; }}}プロジェクトを開始した後、ゲートウェイからアクセスしてみましょう。
2。Zuul Fallbackに関する質問
1。Zuulのタイムアウトの問題について:
この問題にはオンラインで多くの解決策がありますが、ソースコードも投稿したいと思います。このクラスでは、このクラスでヒストリックスとリボンを統合するこのクラスに注意してください。
/ * * Copyright 2013-2016元の著者または著者。 * * Apacheライセンス、バージョン2.0(「ライセンス」)に基づいてライセンスされています。 *ライセンスに準拠している場合を除き、このファイルを使用することはできません。 *ライセンスのコピーを取得することができます * * http://www.apache.org/licenses/license-2.0 * *該当する法律で要求されていない場合、または書面で合意しない限り、ライセンスに基づいて配布されるソフトウェア *は、保証または条件なしで「現状」に分配されます。 *権限を管理する特定の言語のライセンスと、ライセンスに基づく制限を参照してください。 * */package org.springframework.cloud.netflix.zuul.filters.route.support;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration;import springframework.cloud.netflix.ribbon.ribbonhtttpresponse; Import org.springframework.cloud.netflix.ribbon.support.abstractloadbalancingclient; Import org.springframework.cloud.netflix.ribbon.support.contextawareqest; springframework.cloud.netflix.zuul.filters.zuulproperties; Import org.springframework.cloud.netflix.zuul.filters.route.rute.ribboncommand; Import org.springframework.cloud.netflix.zuul.filtters.rute.-rutte.-rutte.-roud.-- absumcmnte. -rudexte org.springframework.cloud.netflix.zuul.filters.route.zuulfallbackprovider; import org.springframework.cloud.netflix.zuul.filters.route.fallbackprovider; Import org.springframework.http.client.client.clienthttprespons; com.netflix.client.AbstractLoadBalancerAwareClient;import com.netflix.client.ClientRequest;import com.netflix.client.config.DefaultClientConfigImpl;import com.netflix.client.config.IClientConfig;import com.netflix.client.config.IClientConfigKey;import com.netflix.client.http.httpresponse;インポートcom.netflix.config.dynamicintproperty; Import com.netflix.config.dynamicpropertyfactory; Import com.netflix.hystrix.hystrix.hystrixcommand; com.netflix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix. com.netflix.hystrix.HystrixCommandKey;import com.netflix.hystrix.HystrixCommandProperties;import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;import com.netflix.hystrix.HystrixThreadPoolKey;import com.netflix.zuul.constants.zuulconstants;インポートcom.netflix.zuul.context.requestcontext;/** * @author spencer gibb */public abstract class abstribboncommand <lbc <lbc extends extends abstractloctoldabbalancerawareclient <rs httpresponse> extends hystrixcommand <clienthttpresponse> ribboncommand {private static final logger = logfactory.getlog(abstractribboncommand.class);保護された最終LBCクライアント。保護されたRibbonCommandContextコンテキスト。保護されたZuulfallBackProvider ZuulfallBackProvider;保護されたiClientConfig構成。 public abstractribboncommand(LBCクライアント、RibbonCommandContext Context、ZuulProperties ZuulProperties){this( "default"、client、context、zuulproperties); } public abstractribboncommand(String CommandKey、LBC Client、RibbonCommandContext Context、ZuulProperties ZuulProperties){this(commandkey、client、context、zuulproperties、null); } public abstractribboncommand(String CommandKey、LBC Client、RibbonCommandContext Context、ZuulProperties ZuulProperties、ZuulfallBackProvider FallbackProvider){This(This(This)(This(This)) } public abstractribboncommand(String CommandKey、LBC Client、RibbonCommandContext Context、ZuulProperties ZuulProperties、ZuulfallBackProvider FallbackProvider、IclientConfig config){this(getsetter(commandkey、zuulporperties、contition、contembution、contember、fallbackprovider、fallbackprovider、 }保護されたAbstractribboncommand(Setter Setter、LBC Client、RibbonCommandContextコンテキスト、ZuulfallBackProvider FallbackProvider、IclientConfig config){super(setter); this.client = client; this.context = context; this.zuulfallbackprovider = fallbackProvider; this.config = config; }保護されたstatic hystrixcommandproperties.setter createSetter(iClientConfig config、string commandkey、zuulproperties zuulproperties){int hystrixtimeout = gethystrixtimeout(config、commandkey); return HystrixCommandProperties.setter()。 } protected static int gethystrixtimeout(iclientConfig config、string commandkey){int ribbontimeout = getRibbontimeout(config、commandKey); DynamicPropertyFactory DynamicPropertyFactory = dynamicPropertyFactory.getInstance(); int defaulthystrixtimeout = dynamicpropertyfactory.getintproperty( "hystrix.command.default.execution.isolation.thread.timeoutinmilliseconds"、0).get(); int commandhystrixtimeout = dynamicPropertyFactory.getIntProperty( "hystrix.command。" + commandkey + ".execution.isolation.thread.timeoutinmilliseconds"、0).get(); int hystrixtimeout; if(commandhystrixtimeout> 0){hystrixtimeout = commandhystrixtimeout; } else if(defaulthystrixtimeout> 0){hystrixtimeout = defaulthystrixtimeout; } else {hystrixtimeout = ribbontimeout; } if(hystrixtimeout <ribbontimeout){logger.warn( "" + hystrixtimeout + "for the command" + commandkey + "のHystrixタイムアウトは、リボン読み取りと接続のタイムアウトの組み合わせよりも低く設定されています。 } HystrixTimeoutを返します。 } protected static int getribbontimeout(iclientConfig config、string commandkey){int ribbontimeout; if(config == null){ribbontimeout = ribbonclientconfiguration.default_reaut + ribbonclientconfiguration.default_connect_timeout; } else {int ribbonreadtimeout = gettimeout(config、commandkey、 "readtimeout"、iclientconfigkey.keys.readuout、ribbonclientconfiguration.default_read_timeout); int ribbonconnectimeout = getTimeout(config、commandkey、 "connecttimeout"、iclientConfigkey.keys.connecttimeout、ribbonclientconfiguration.default_connect_timeout); int maxautoretries = gettimeout(config、commandkey、 "maxautoretries"、iclientconfigkey.keys.maxautoretries、defaultclientconfigimpl.default_max_auto_retries); int maxautoretriesnextserver = getTimeout(config、commandkey、 "maxautoretriesnextserver"、iclientconfigkey.keys.maxautoretriesnextserver、defaultclientconfigimpl.default_max_auto_retries_next_next_server); ribbontimeout =(ribbonreadtimeout + ribbonconnecttimeout) *(maxautoretries + 1) *(maxautoretriesnextserver + 1); } ribbontimeoutを返します。 } private static int getTimeout(iClientConfig config、string commandkey、string property、iClientconfigkey <integer> configkey、int defaultValue){dynamicPropertyFactory dynamicPropertyFactory = dynamicPropertyFactory.getInstance(); return dynamicPropertyFactory.getIntProperty(commandKey + "。" + config.getNamesPace() + " } @deprecated // 2.0.xで削除された2.0.x保護された静的セッターgetSetter(final string commandkey、zuulproperties zuulproperties){return getsetter(commandkey、zuulproperties、null); }保護された静的セッターgetSetter(最終文字列commandKey、zuulproperties zuulproperties、iclientconfig config){// @formatter:off setter commandsetter = setter.withgroupkey(hystrixcommandgroupkey.factory.askey( "ribboncommand"))。 final hystrixcommandproperties.setter setter = createsetter(config、commandkey、zuulproperties); if(zuulproperties.getribbonisolationstrategy()== executionisolationstrategy.semaphore){final string name = zuulconstants.zuul_eureka + commandkey + ".semaphore.maxsemaphores"; //これは既に隔離されている最終的なDynamicIntProperty value = dynamicPropertyFactory.getInstance().getIntProperty(name、zuulproperties.getSemaphore()。getMaxSemaphores()); setter.withexecutionisolationsemaphoremaxconcurrentRequests(value.get()); } else if(zuulproperties.getthreadpool()。isuseseparateThreadpools()){final String threadPoolkey = zuulproperties.getThreadPool()。 commandsetter.andthreadpoolkey(hystrixthreadpoolkey.factory.askey(threadpoolkey)); } return commandsetter.andCommandPropertiesDefaults(setter); // @formatter:on} @Override Protected ClientHttPresponse run()throws Exception {final requestContext context = requestContext.getCurrentContext(); rq request = createrequest(); RS応答; boolean retryableclient = this.client instance of abstractloadbalanceclient &&((abstractloadbalancingclient)this.client).IsclientRetryable((contextAwareRequest)request); if(retryableclient){respons = this.client.execute(request、config); } else {response = this.client.executewithloadbalancer(request、config); } context.set( "ribbonResponse"、response); // Hystrixコマンドが//応答によって保持されている基礎となるHTTP接続をリリースした場合、HTTPResponseを明示的に閉じます。 // if(this.isresponsetimedout()){if(respons!= null){respons.close(); }} new Ribbonhttpresponse(Response)を返します。 } @Override Protected ClientHttPresponse getFallback(){if(zuulfallbackProvider!= null){return getFallBackResponse(); } super.getfallback()を返します。 } protected clienthttpresponse get fallbackResponse(){if(zuulfallbackprovider of fallbackProvider){throwable cause = getFailedExecutionException();原因=原因== null? getexecutionexception():couse; if(courd == null){zuulfallbackprovider.fallbackResponse(); } else {return((fallbackprovider)zuulfallbackprovider).fallbackResponse(cause); }} zuulfallbackprovider.fallbackResponse()を返します。 } public lbc getClient(){return client; } public RibbonCommandContext getContext(){return Context; }保護された要約rq createrequest()スロー例外;}注: getribbontimeoutメソッドとgethystrixtimeoutメソッド。これらの2つのメソッドの値はルートの名前です。たとえば、http:// localhost:8088/order-server/xxxにアクセスするには、注文サーバーサービスにアクセスした場合、CommandKeyはOrder-Serverです
ソースコードによると、最初にゲートウェイサーバータイムアウトパラメーターを設定します。
#Globalリボン設定リボン:ConnectTimeOut:3000 ReadTimeOut:3000HyStrix:コマンド:デフォルト:実行:分離:スレッド:TimeOutinMilliseConds:3000Zuul:HOST:CONNECTTIMEOUTMILLIS:10000
もちろん、注文サーバーのリボンのタイムアウトパラメーターを個別に設定することもできます。 Zuulのフォールバック効果を示すために、ここでHystrixタイムアウトを少し短く設定します。もちろん、Hystrixのデフォルトのタイムアウトをリボンのタイムアウトよりも短く設定しないことをお勧めします。この状況は、ソースコードで当社について警告されています。
次に、次のメソッドを注文サーバーの下に追加します。
@getMapping( "/sleep/{sleeptime}")パブリックストリングスリープ(@pathvariable long sleeptime)throws arturtedexception {timeunit.seconds.sleep(sleeptime); 「成功」を返します。 }2。Zuulのフォールバック方法
ZuulfallbackProviderインターフェイスを実装して、コードを実装できます。
パッケージcom.hzgj.lyrk.springcloud.gateway.server.filter; import com.google.common.collect.immutablemap; Import com.google.gson.gsonbuilder; Import org.springframework.cloud.netflix.zuul.filters. zuul.wulter. springframework.http.httpheaders; import org.springframework.http.httpstatus; Import org.springframework.http.mediatype; Import org.springframework.http.client.clienthttpresponse java.io.bytearrayinputStream; Import java.io.ioexception; Import java.io.inputStream; Import java.time.localdatetime; Import java.local.localtime; @componcentpublic class fallbackhandlerements zuulfallbackprovider {@override public String attroute attroute() "*"; } @Override public clienthttpresponse fallbackResponse(){return new clienthttpresponse(){@override public httpstatus getstatuscode()throws ioexception {return httpstatus.ok; } @Override public int getRawStatusCode()throws ioException {return 200; } @Override public String getStatustext()throws ioException {return "ok"; } @Override public void close(){} @Override public inputstream getBody()throws {string result = new gsonbuilder()。create()新しいbytearrayinputStream(result.getBytes())を返します。 } @override public httpheaders getheaders(){httpheaders headers = new httpheaders(); headers.setContentType(mediatype.application_json);ヘッダーを返します。 }}; }}この時点で、http:// localhost:8088/order-server/sleep/6にアクセスし、次の結果を取得します。
訪問するとき:http:// localhost:8088/order-server/sleep/1、次の結果が得られます。
要約します
上記は、この記事のコンテンツ全体です。この記事の内容には、すべての人の研究や仕事に特定の参照値があることを願っています。ご質問がある場合は、メッセージを残してコミュニケーションをとることができます。 wulin.comへのご支援ありがとうございます。