Vorwort
Zuul ist eine von Netflix bereitgestellte Open -Source -Komponente, die sich zur Bereitstellung dynamischer Routing, Überwachung, Belastbarkeit, Sicherheit und anderer Edgedienste auf der Cloud -Plattform verpflichtet hat. Es gibt auch viele Unternehmen, die es als wichtigen Bestandteil des Gateways verwenden. In diesem Jahr beschloss die Architekturgruppe des Unternehmens, ein Gateway -Produkt zu entwickeln, das dynamische Routing, dynamische Berechtigungen, aktuelle Limit -Quoten und andere Funktionen zu integrieren, ein einheitliches externes Netzwerkanrufmanagement für Projekte in anderen Abteilungen bereitzustellen und schließlich ein Produkt zu bilden (ALI hat tatsächlich eine ausgereifte Gateway -Produkte in dieser Beachtung, aber es ist nicht geeignet für personalisierte Konfigurationen, und es gibt keine integrierten Zuverlässigkeiten, aber es ist keine integrierten Beschränkungen, und es gibt keine integrierten Zuverlässigkeiten, aber es gibt keine integrierten Zuverlässigkeiten, aber es gibt keine laufenden Beschränkungen.
In diesem Artikel wird hauptsächlich die relevanten Inhalte über die Frühlings -Cloud -Zuul Unified Exception -Handhabung und -Fallback vorgestellt. Es wird für Ihre Referenz und Ihr Lernen geteilt. Ich werde unten nicht viel sagen. Schauen wir uns die detaillierte Einführung zusammen an.
1. Einheitliche Ausnahmehandhabung im Filter
Tatsächlich gibt es in der Edgware SR2 -Version von SpringCloud eine einheitliche Behandlung von Fehlern in Zuulfilter, aber in der tatsächlichen Entwicklung habe jedes Team seine eigenen Verarbeitungsspezifikationen für die Antwortmethoden der Fehler. Wie mache ich also benutzerdefinierte Ausnahmebehandlung?
Wir können zuerst auf den von SpringCloud bereitgestellten SendErrorFilter verweisen:
/ * * Copyright 2013-2015 Der ursprüngliche Autor oder Autoren. * * Lizenziert unter der Apache -Lizenz, Version 2.0 (die "Lizenz"); * Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. * Sie können eine Kopie der Lizenz unter * * http://www.apache.org/licenses/license-2.0 * * * *, sofern nach geltendem Recht oder schriftlich gefordert oder schriftlich gefordert wird, Software *, die im Rahmen der Lizenz verteilt ist, auf "As "basis * ohne Gewährleistungen oder Bedingungen jeglicher Art verteilt oder implementiert. * Siehe die Lizenz für die spezifischen Sprachberechtigungen und * Einschränkungen im Rahmen der Lizenz. */Paket org.springframework.cloud.netflix.zuul.filters.post; import Javax.servlet.RequestDispatcher; import Javax.servlet.http.httpservletrequest; import.http.httpserd; org.apache.commons.logging.logfactory; import org.springframework.beans.factory.Annotation org.springframework org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ERROR_TYPE;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_ERROR_FILTER_ORDER;/** * Error {@link ZuulFilter} that forwards to /error (Standardmäßig) Wenn {@link requestContext#getthrowable ()} nicht null ist. * * @author spencer gibb * /// todo: Wechsel zum Fehlerpaket in Edgwarepublic Class SendErrorFilter erweitert Zuulfilter {private statische endgültige log -log = logFactory.getLog (sendErrorFilter.class); Protected Static Final String send_error_filter_ran = "sendErrorter.ran"; @Value ("$ {error.Path:/error}") privater String -Fehlerpath; @Override public String filterType () {return error_type; } @Override public int filterOrder () {return send_error_filter_order; } @Override public boolean sollteFilter () {requestContext ctx = requestContext.getCurrentContext (); // Nur an ERRORPATH weiterleiten, wenn es nicht weitergeleitet wurde, um CTX.Gethrowable ()! } @Override public Object run () {try {requestContext ctx = requestContext.getCurrentContext (); ZuUlexception Exception = findZuulexception (ctx.gethrowable ()); HttpServletRequest request = ctx.getRequest (); Request.SetAttribute ("javax.servlet.Error.status_code", exception.nstatuscode); log.warn ("Fehler während der Filterung", Ausnahme); Request.SetAttribute ("javax.servlet.Error.Exception", Ausnahme); 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 (! Dispatcher.forward (Request, ctx.getResponse ()); }}} catch (Exception ex) {reflectionutils.rethrowRuntimeException (ex); } return null; } ZuUlexception findzuUlexception (throwable throwable) {if (throwable.getCause () Instanz von Zuulruntimeexception) {// Dies war ein Fehler, der von einem der lokalen Filter zurückgegeben wurde (ZuUlexception) Throwable.getCause (). GetCause (); } if (throwable.getCause () Instanz von ZuUlexception) {// Wicked Zuul Exception Return (ZuUlexception) Throwable.getCause (); } if (throwable Instanz der ZuUlexception) {// Ausnahme, die durch Zuul Lifecycle Return (ZuUlexception) Throwable; } // fallback, sollte niemals hierher kommen. Zurück neu zulexception (throwable, httpServletResponse.sc_internal_server_error, null); } public void setErrorPath (String errorPath) {this.ErrorPath = errorPath; }}Hier finden wir mehrere wichtige Punkte:
1) Im obigen Code können wir feststellen, dass der Filter die entsprechenden Fehlerinformationen in die Anforderung eingerichtet hat:
Request.SetAttribute ("javax.servlet.Error.status_code", exception.nstatuscode);
Request.SetAttribute ("javax.servlet.Error.Exception", Ausnahme);
Request.SetAttribute ("javax.servlet.Error.Message", Exception.ErrorCause);
2) Nachdem der Fehler verarbeitet wurde, wird er zur Verarbeitung an die XXX/Fehleradresse weitergeleitet
Dann können wir ein Experiment machen. Wir erstellen einen Filter, der Ausnahmen in das Gateway-Service-Projektmodul auslöst:
Paket com.hzgj.ryrk.springcloud.gateway.server.filter; import com.netflix.zuul.zuulfilter; import lombok.extern.slf4j.slf4j; @Override public String filterType () {return "post"; } @Override public int filterOrder () {return 9; } @Override public boolean sollte filter () {return true; } @Override public Object run () {log.info ("Fehler -Test ..."); neue runimeexception () werfen; // null zurückgeben; }}Dann definieren wir einen Controller, um Fehler zu behandeln:
Paket com.hzgj.ryrk.springcloud.gateway.server.filter; import org.springframework.http.httpstatus; import org.springframework.http.Reption; Import org. org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;@RestControllerpublic class ErrorHandler { @GetMapping(value = "/error") public ResponseEntity<ErrorBean> error(HttpServletRequest request) { String message = request.getAttribute ("javax.servlet.Error.message"). toString (); ERRORBEAN ERRORBEAN = NEW ERRORBEAN (); ERRORBEAN.SETMESSAGE (Nachricht); ERRORBEAN.SETREAME ("Programmfehler"); Neue ResponseEntity <> zurückgeben (Fehlerbean, httpstatus.bad_gateway); } private statische Klassen -Fehlerbean {private String -Nachricht; private String -Vernunft; public String getMessage () {Rückgabenachricht; } public void setMessage (String -Nachricht) {this.message = message; } public String getReason () {Return Reason; } public void setReason (String Reason) {this.Reason = Reason; }}}Versuchen wir nach dem Start des Projekts über das Gateway zugreift:
2. Fragen zu Zuul Fallback
1. In Bezug auf das Timeout -Problem von Zuul:
Es gibt viele Lösungen für dieses Problem online, aber ich möchte auch den Quellcode veröffentlichen. Bitte achten Sie auf diese KlassenabstracttribbonCommand, die Hytrix und Ribbon in dieser Klasse integriert.
/ * * Copyright 2013-2016 Der ursprüngliche Autor oder Autoren. * * Lizenziert unter der Apache -Lizenz, Version 2.0 (die "Lizenz"); * Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. * Sie können eine Kopie der Lizenz unter * * http://www.apache.org/licenses/license-2.0 * * * *, sofern nach geltendem Recht oder schriftlich gefordert oder schriftlich gefordert wird, Software *, die im Rahmen der Lizenz verteilt ist, auf "As "basis * ohne Gewährleistungen oder Bedingungen jeglicher Art verteilt oder implementiert. * Siehe die Lizenz für die spezifischen Sprachberechtigungen und * Einschränkungen im Rahmen der Lizenz. * */Paket org.springframework.cloud.netflix.zuul.filters.route.Support; org.apache.commons.logging.log; org.springframework.cloud.netflix.ribbon.ribbonhttpesponse; import org.springframework.cloud.netflix.ribbon.support.abstractloadBalancingClient; org.springframework.cloud.netflix.zuul.filters.zuulproperties; import org.springFramework.cloud.netflix.zu.filters.route.ribboncommand; Import org.springFramework.Netflix.Zuul.filter.Routter.RoUt.Filter.Filter.Filter.Filter.Filter.Filter.Filter.Filter.Filter.RoUt.Filter.Routter.RoUt.Filter.ROUTTER.RICT; org.springframework.cloud.netflix.zuul.filters.route.zuulfallbackProvider; import org.springframework.cloud.netflix.zuul.filters.Route.FallbackProvider; com.netflix.client.abstractloadBalancerawareClient; import com.netflix.client.clientRequest; import com.netflix.client.config.DefaultClientConFigimpl; com.netflix.client.config.iclientconfig; com.netflix.client.http.httpesponse; import com.netflix.config.dynamicintProperty; importieren com.netflix.config.dynamicpropertyfactory; import com.netflix.hystrix.hystrixcommand; com.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix.hystrix. com.netflix.hystrix.hystrixcommandkey; import com.netflix.hystrix.hystrixcommandproperties; import com.netflix.hystrix.hystrixcommandproperties.executionisolationsstoolkey; com.netflix.zuul.constants.ZuulConstants;import com.netflix.zuul.context.RequestContext;/** * @author Spencer Gibb */public abstract class AbstractRibbonCommand<LBC extends AbstractLoadBalancerAwareClient<RQ, RS>, RQ extends ClientRequest, RS extends HttpResponse> erweitert hystrixCommand <clienthttPesponse> implementiert ribbonCommand {private static final logger = logfactory.getLog (AbtractribbonCommand.class); geschützter endgültiger LBC -Client; geschützter RibbonCommandContext -Kontext; geschützter ZuulfallbackProvider ZuulfallbackProvider; Protected iClientConfig -Konfiguration; public abstracttribbonCommand (LBC -Client, RibbonCommandContext -Kontext, ZuulProperties Zuulproperties) {this ("Standard", Client, Kontext, ZuulProperties); } public abStraTRibbonCommand (String -Befehlskey, LBC -Client, RibbonCommandContext -Kontext, Zuulproperties ZuulProperties) {this (commandkeyKey, Client, Kontext, Zuulproperties, Null); } public abStractribBonCommand (String CommandKey, LBC -Client, RibbonCommandContext -Kontext, Zuulproperties ZuulProperties, ZuulfallbackProvider FallbackProvider) {this (crandentyKey, Client, Kontext, ZuulProperties, FallbackProvider, NULL, NULL, NULL); } public AbstractRibbonCommand(String commandKey, LBC client, RibbonCommandContext context, ZuulProperties zuulProperties, ZuulFallbackProvider fallbackProvider, IClientConfig config) { this(getSetter(commandKey, zuulProperties, config), client, context, fallbackProvider, config); } Protected AbtracTribBonCommand (Setter Setter, LBC Client, RibbonCommandContext -Kontext, ZuulfallbackProvider fallbackProvider, IclientConfig config) {Super (Setter); this.client = client; this.context = context; this.zuulfallbackProvider = fallbackProvider; this.config = config; } protected static hystrixCommandProperties.setter erstelltesetter (iclientConfig config, String commandKey, ZuulProperties ZuulProperties) {int hyStrixTimeout = GethyStrixTimeout (config, commandentyKey); return hystrixCommandProperties.setter (). WithExecutionisolationsstrategy (ZuulProperties.getribbonisolationsstrategy ()). WithExecutionTimeoutinMilliseconds (hystrixTimeout); } protected static int gethyStrixTimeout (iclientConfig config, String commandKey) {int Ribbontimeout = getribBontimeout (config, commandeyKey); 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 = bibbontimeout; } if (hystrixTimeout <bibbontimeout) {logger.warn ("Die Hystrix -Zeitüberschreitung von" + hystrixTimeout + "MS für den Befehl" + commandekey + "ist niedriger als die Kombination aus dem Timeout und der Verbindung von Timeout" + bibbontimeout + "ms."); } return hystrixTimeout; } Protected static int getribbontimeout (iclientConfig config, String commandKey) {int RibbontimeOut; if (config == null) {bibbontimeout = ribbonclientConfiguration.default_read_timeout + ribbonclientConfiguration.default_connect_timeout; } else {int RibbonReadTimeout = GetTimeout (config, commandentyKey, "readtimeout", iclientConFigkey.keys.readtimeout, RibbonClientConfiguration.Default_read_timeout); int RibbonConnectTimeout = GetTimeout (config, commandentyKey, "ConnectTimeout", iclientConFigkey.keys.connectTimeout, RibbonClientConfiguration.default_connect_timeout); int maxAutoretries = GetTimeout (config, commandkeyKey, "maxAutoretries", iclientConFigkey.keys.maxAutoretries, defaultClientConfigimpl.Default_Max_auto_retries); int maxAutoretriiesNextServer = GetTimeout (config, commandentyKey, "maxAutoretriiesNextServer", iclientConFigkey.Keys.maxAutoretriiesNextServer, DefaultClientConFigImpl.Default_Max_auto_Ries_Next_server); bibbontimeout = (RibbonReadTimeout + RibbonConnectTimeout) * (maxAutoretries + 1) * (maxAutoretriiesNextServer + 1); } return bibbontimeout; } private statische Int GetTimeout (iClientConfig -Konfiguration, String CommandKey, String -Eigenschaft, iClientConFigkey <GanzEger> configKey, int defaultValue) {DynamicPropertyFactory DynamicPropertyFactory = DynamicPropertyFactory.getInstance (); return dynamicPropertyFactory.getIntProperty (commandkey + "." + config.getNameSpace () + "." + Eigenschaft, config.get (configKey, StandardValue)). get (); } @Deprecated // Todo in 2.0.x geschütztem statischer Setter getSetter (Final String CommandKey, ZuulProperties ZuulProperties) {return getsetter (commandectyKey, Zuulproperties, Null); } Protected Static Setter getsetter (Final String CommandKey, ZuulProperties ZuulProperties, iClientConfig -Konfiguration) {// @Formatter: Off Settersetter = Setter. .AndcommandKey (hystrixCommandkey.factory.askey (commandkey)); endgültig hystrixCommandProperties.Setter Setter = createsSerTter (config, commandentyKey, ZuulProperties); if (ZuulProperties.getribbonisolationsstrategy () == executionisolationsstrategy.semaphore) {Final String name = ZuulConstants.zuul_eureka + candrapeKey + ".semaphore.maxsemaphores"; // Wir möchten standardmäßig mit Semaphore-Isolation standhalten, da diese Wraps // 2 andere Befehle, die bereits thread isoliert sind, endgültig dynamicintProperty value = dynamicPropertyfactory.getInstance () .GetintProperty (Name, ZuulProperties.getSemaphore (). getMaxsemaphores (); setter.withexecutionisolationsemaphoremaxconcurrentRequests (value.get ()); } else if (ZuulProperties.Gethreadpool (). IsuseSeparatTheadpools ()) {Final String threadpoolkey = ZuulProperties.Gethreadpool (). GetThreadpoolkeyPrefix () + commandkey; commandsetter.andthreadpoolkey (hystrixThreadpoolkey.factory.askey (threadpoolkey)); } return commandSetter.andCommandPropertiesDefaults (Setter); // @Formatter: on} @Override Protected clienthttPesponse run () löst Ausnahme aus {endgültig RequestContext context = RequestContext.getCurrentContext (); RQ Request = CreateRequest (); RS -Antwort; boolean retryableClient = this.client InstanceOf AbstractloadBalancingClient && ((AbstractLoadBalancingClient) this.client) .IsclentRetRyable ((contextAwareRequest) Anfrage); if (retryableClient) {response = this.client.execute (request, config); } else {response = this.client.executeWithBoadBalancer (Request, config); } context.set ("RibbonResponse", Antwort); // Schließen Sie explizit die HTTPResponse, wenn der Befehl hystrix an // die zugrunde liegende HTTP -Verbindung von der Antwort veröffentlicht hat. // if (this.isresponsetimedout ()) {if (response! = null) {response.close (); }} return New RibbonHttPesponse (Antwort); } @Override Protected clienthttPesponse getFallback () {if (ZuulfallbackProvider! = Null) {return getFallbackResponse (); } return Super.getFackback (); } protected clienthttPesponse getFallbackResponse () {if (ZuulfallbackProvider Instanz von FallbackProvider) {Throwable cause = getFailEdexexception (); Ursache = Ursache == NULL? GetExecutionException (): Ursache; if (cause == null) {ZuulfallbackProvider.FallbackResponse (); } else {return ((fallbackProvider) ZuulfallbackProvider) .FallbackResponse (Ursache); }} return ZuulfallbackProvider.FallbackResponse (); } public LBC getClient () {return client; } public RibbonCommandContext getContext () {return context; } Protected Abstract RQ CreateRequest () löst Ausnahme aus;}Bitte beachten Sie: Getribbontimeout -Methode und GethystrixTimeout -Methode, wobei der Wert dieser beiden Methoden der BefehlsKey der Name der Route ist. Wenn wir beispielsweise besuchen: http: // localhost: 8088/orderverver/xxx, um auf den Order-Server-Dienst zuzugreifen, dann ist CommandKey Order-Server
Gemäß dem Quellcode haben wir zunächst die Timeout-Parameter von Gateway-Server festgelegt:
#Global Ribbon Einstellungen Ribbon: ConnectTimeOut: 3000 ReadTimeout: 3000Hystrix: Befehl: Standard: Ausführung: Isolation: Thread: TimeoutinMilliseconds: 3000Zuul: Host: ConnectTimeOutmillis: 10000
Natürlich können Sie auch die Timeout-Parameter des Bandes für Ordenserver separat festlegen: order-server.ribbon.xxxx = xxx. Um den Fallback -Effekt in Zuul zu demonstrieren, habe ich die Hytrix -Zeitüberschreitung hier etwas kürzer festgelegt. Natürlich ist es am besten, die Standardzeit von Hytrix nicht so zu setzen, dass es kürzer ist als das Timeout of Ribbon. Diese Situation wurde von uns im Quellcode gewarnt.
Anschließend fügen wir die folgende Methode unter Ordenserver hinzu:
@Getmapping ("/sleep/{sleeptime}") public String schlaf (@PathVariable Long Sleepime) löst InterruptedException {TimeUnit.seconds.sleep (SleepTime) aus; zurück "Erfolg"; }2. Zuuls Fallback -Methode
Wir können die ZulfallbackProvider -Schnittstelle implementieren und den Code implementieren:
Paket com.hzgj.ryrk.springcloud.gateway.server.filter; import com.google.common.collect.immutablemap; import com.google.gson.gsonbuilder; org. Java.io.BytearrayInputStream; Import Java.io.ioxception; Import Java.io.inputStream; Import Java.time "*"; } @Override public ClientHttPesponse fallbackResponse () {return New ClienthttPesponse () {@Override public httpstatus getStatusCode () löscht IOException {return httpstatus.ok; } @Override public int getRawStatusCode () löst ioException {return 200; } @Override public String getStatUntext () löscht ioException {return "OK"; } @Override public void close () {} @Override public InputStream getBody () löscht ioException {String result = new gsonBuilder (). Create (). Tojson (immutablemap.of ("Fehlercode", 500, "Inhalt", "Anfrage fehlgeschlagen", "Zeit", localDatetime.now ()); Neue BytearrayInputStream zurückgeben (result.getBytes ()); } @Override public httpheaders getheaders () {httpheaders headers = new httpheaders (); Headers.SetContentType (minyType.Application_json); Rückgabebehörungen; }}; }}Zu diesem Zeitpunkt besuchen wir: http: // localhost: 8088/orderverver/sleep/6 und erhalten die folgenden Ergebnisse:
Wenn wir besuchen: http: // localhost: 8088/orderver/sleep/1, erhalten wir das folgende Ergebnis:
Zusammenfassen
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Referenzwert für das Studium oder die Arbeit eines jeden hat. Wenn Sie Fragen haben, können Sie eine Nachricht zur Kommunikation überlassen. Vielen Dank für Ihre Unterstützung bei Wulin.com.