Предисловие
Zuul - это компонент с открытым исходным кодом, предоставляемый Netflix, приверженным обеспечению динамической маршрутизации, мониторинга, устойчивости, безопасности и других сервисов Edge на облачной платформе. Есть также много компаний, которые используют его в качестве важной части шлюза. В этом году архитектурная группа компании решила разработать продукт Gateway, интегрировать динамическую маршрутизацию, динамические разрешения, текущие ограниченные квоты и другие функции, обеспечивая единое управление внешними сетевыми вызовами для проектов в других отделениях и, наконец, формирование продукта (ALI фактически имеет зрелые продукты Gateway в этом отношении, но он не подходит для персонализированных конфигураций, и не имеет интегрированных проникновений и текущих ограничений).
В этой статье в основном представлены соответствующий контент о обработке и запасной обработке исключенных исключений Spring Cloud. Это обменивается вашей ссылкой и обучением. Я не скажу многое ниже, давайте посмотрим на подробное введение вместе.
1. Обработка единой исключения в фильтре
Фактически, в версии Springcloud Edgware SR2 существует единое обращение с ошибками в Zuulfilter, но в реальном развитии я думаю, что у каждой команды есть свои собственные спецификации обработки для методов ответа ошибок. Так как же сделать пользовательскую обработку исключений?
Сначала мы можем обратиться к SendErrorFilter, предоставленному SpringCloud:
/ * * 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.servlet.http.httpservelponse; import..servale.http.httpservelsesponse; org.apache.commons.logging.logfactory; import org.springframework.beans.factory.annotation.value; import org.springframework.cloud.netflix.zuul.util.zuulruntimeexcept org.springframework.util.stringutils; import com.netflix.zuul.zuulfilter; import com.netflix.zuul.context.requestcontext; import com.netflix.zuul.exception.zuulexception; импорт статический org.springframework.cloud.netflix.zuul.filters.support.filterConstants.error_type; Import static org.springframework.cloud.netflix.zuul.filters.support.filterConstants.send_Error /error (по умолчанию), если {@link requestContext#getThrowable ()} не является нулевым. * * @author spencer gibb * /// todo: перемещение в пакет ошибок в edgwarepublic class senderrorfilter extends zuulfilter {private Static final log = logfactory.getlog (senderrorfilter.class); Защищенная статическая конечная строка send_error_filter_ran = "senderrorfilter.ran"; @Value ("$ {error.path:/erry}") частная строка Errorpath; @Override public String filterType () {return error_type; } @Override public int filterorder () {return send_error_filter_order; } @Override public boolean supfilter () {requestContext ctx = requestContext.getCurrentContext (); // Справляйтесь только в Errorpath, если он не был отправлен, чтобы уже вернуть ctx.getThrowable ()! = null &&! ctx.getboolean (send_error_filter_ran, false); } @Override public Object run () {try {requestContext ctx = requestContext.getCurrentContext (); Zuulexception exception = findzuulexception (ctx.getThrowable ()); Httpservlectrequest request = ctx.getRequest (); request.setattribute ("javax.servlet.error.status_code", exception.nstatuscode); log.warn («ошибка во время фильтрации», исключение); request.setattribute ("javax.servlet.error.exception", 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); } return null; } Zuulexception findzuulexception (throwable throwable) {if (throwable.getCaue () экземпляр Zuulruntimeexception) {// Это был сбой, инициированный одним из локальных фильтров return (Zuulexception) throwable.getCause (). GetCause (); } if (throwable.getCaue () exantef Zuulexception) {// Обернутый Zuul Exception return (zuulexception) throwable.getCause (); } if (бросаемый экземпляр Zuulexception) {// Исключение, брошенное Zuul Lifecycle return (Zuulexception) Throwable; } // Запасение, никогда не должно быть здесь возвращать новое 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", Exception);
request.setattribute ("javax.servlet.error.message", Exception.errorcause);
2) После обработки ошибки она будет направлена на адрес xxx/ошибки для обработки
Тогда мы можем провести эксперимент. Мы создаем фильтр, который бросает исключения в модуле проекта Gateway-Service:
пакет com.hzgj.lyrk.springcloud.gateway.server.filter; import com.netflix.zuul.zuulfilter; import lombok.extern.slf4j.slf4j; import org.springframework.stereotype.component;@component@slf4jpublic class myzuuL public String filtertype () {return "post"; } @Override public int filterorder () {return 9; } @Override public boolean supfilter () {return true; } @Override public Object run () {log.info ("run urer test ..."); бросить новый runtimeexception (); // вернуть NULL; }}Затем мы определяем контроллер для обработки ошибок:
Пакет com.hzgj.lyrk.springcloud.gateway.server.filter; import org.springframework.http.httpstatus; импорт org.springframework.http.respessonty; import org.spramework.web.bindation.gretmapping; org.springframework.web.bind.annotation.restcontroller; import javax.servlet.http.httpservletrequest; @restcontrollerpublic class errorhandler {@getmapping (value = "/error") publiceentty <errorbean> error (httpserveltrequest (value = ") request.getAttribute ("javax.servlet.error.message"). ToString (); Ошибка ошибка ошибка = новый ошибок (); errorbean.setMessage (сообщение); errorbean.setReason («ошибка программы»); вернуть новую responseentity <> (ошибка, httpstatus.bad_gateway); } private Static Class ErrorBean {Private String Message; частная строковая разум; public String getMessage () {return message; } public void setMessage (String Message) {this.message = сообщение; } public String getReason () {return insode; } public void setReason (String Sanys) {this.Reason = couns; }}}После начала проекта давайте попробуем получить доступ к нему через шлюз:
2. Вопросы о Zuul Swarkback
1. Относительно задачи с тайм -аутом Zuul:
Есть много решений этой проблемы в Интернете, но я также хочу опубликовать исходный код. Пожалуйста, обратите внимание на этот класс AbstractribbonCommand, который интегрирует Hystrix и ленту в этом классе.
/ * * 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.sprimework.cloud.netflix.ribbon.ribboncligrade; org.springframework.cloud.netflix.ribbon.ribbonhttpresponse; импорт org.springframework.cloud.netflix.ribbon.support.abstractlancebanceclient; import org.springframework.cloud.netflix.ribbon.support.contextawarequest; org.springframework.cloud.netflix.zuul.filters.zuulproperties; импорт org.springframework.cloud.netflix.zuul.filters.route.ribboncommand; импорт org.springframework.cloud.netflix.zuul.filters.route.ribboncom. org.springframework.cloud.netflix.zuul.filters.route.zuulfallbackprovider; import org.springframework.cloud.netflix.zuul.filters.route.fallbackprovider; import.springframework.http.client.clienthtpresse; com.netflix.client.abstractloadbalancerawareclient; import com.netflix.client.clientRequest; import com.netflix.client.config.defaultclientConfigimpl; import com.netflix.client.config.iclientConfig; importfiglix.client.config.iclientCkey; com.netflix.client.http.httpresponse; import com.netflix.config.dynamicintproperty; import com.netflix.config.dynamicpropertyfactory; import com.netflix.hystrix.hystrixcommand; import com.netflix.hystrix.hystrixcommandgroupkey; com.netflix.hystrix.hystrixcommandkey; import com.netflix.hystrix.hystrixcommandproperties; import com.netflix.hystrix.hystrixcommandproperties.executionisolationtrategy; import com.netflix.hystrix.hystrixtrixtrixpools com.netflix.zuul.constants.zuulconstants; import com.netflix.zuul.context.RequestContext;/** * @Author spencer gibb */public abstract class classcommand <lbc extrabledendsbalancerawareclient <rq>, rq extends clientspest extendess extendes Hystrixcommand <clienthttpresponse> реализует ribboncommand {private static final logger = logfactory.getlog (actremactribboncommand.class); Защищенный финальный клиент LBC; защищенный ленточный контекст; Защищенный zuulfallbackprovider Zuulfallbackprovider; Защищенный конфигурация iClientConfig; Public AbstractribbonCommand (LBC Client, RibbonCommandContext Context, ZuulProperties ZuulProperties) {this («По умолчанию», клиент, контекст, ZuulProperties); } public AbstractribbonCommand (String CommandKey, LBC Client, ClebbonCommandContext Context, ZuulProperties ZuulProperties) {this (commandkey, client, контекст, ZuulProperties, null); } public AbstractribbonCommand (String Commandkey, LBC Client, RibbonCommandContext Context, ZuulProperties ZuulProperties, ZuulfallbackProvider SharkbackProvider) {This (CommandKey, Client, Context, ZuulProperties, SwarkbackProvider, Null); } public AbstractribbonCommand (String Commandkey, LBC Client, ленточный контекст, ZuulProperties ZuulProperties, ZuulfallbackProvider SharkbackProvider, IclientConfig Config) {This (GetSetter (CommandKey, ZuulProperties, Config), Client, Context, FallbackProvider, Config); } Защищенный AbstracTribbonCommand (Setter Setter, LBC Client, ленточный контекст, zuulfallbackprovider sharkbackprovider, iclientconfig config) {super (setter); this.client = client; this.context = context; this.zuulfallbackprovider = sharkbackprovider; this.config = config; } защищенный статический hystrixcommandproperties.setter createSetter (iClientConfig Config, String CommandKey, ZuulProperties ZuulProperties) {int hystrixTimeout = GethyStrixTimeout (config, commandKey); return hystrixcommandproperties.setter (). withExecutionisolationStrategy (ZuulProperties.getRibbonisolationStrategy ()). withExecutitionTimeOutInmilliseconds (hystrixTimeout); } Защищенный 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 + ". int hystrixtimeout; if (commandhystrixtimeout> 0) {hystrixtimeout = commandhystrixtimeout; } else if (defaulthystrixtimeout> 0) {hystrixtimeout = defaulthystrixtimeout; } else {hystrixtimeout = ribbontimeout; } if (hystrixtimeout <ribbontimeout) {logger.warn («Тайм -аут Hystrix« + hystrixTimeOut + "MS для команды" + commandKey + "установлен ниже комбинации ленты и подключения времени," + ribbontimeout + "MS."); } return hystrixtimeout; } защищенный static int getRibbontimeout (iclientConfig config, string commandkey) {int ribbontimeout; if (config == null) {ribbontimeout = ribbonclientConfiguration.default_read_timeout + ribbonclientConfiguration.default_connect_timeout; } else {int RibbonReadTimeOut = getTimeOut (config, commandKey, "readtimeOut", iclientConfigkey.keys.readtimeOut, ribbonClientConfiguration.default_read_timeout); int RibbonConnecttimeout = getTimeout (config, commandKey, "connectTimeOut", iClientConfigkey.keys.connecttimeOut, rabbonClientConfiguration.default_connect_timeout); int maxautoreties = gettimeout (config, commandkey, "maxautoretries", iclientconfigkey.keys.maxautoretries, defaultClientConfigImpl.default_max_auto_retries); int maxautoretiesnextserver = gettimeout (config, commandkey, "maxautoretriesnexterver", iclientConfigkey.keys.maxautoreRiesNextServer, defaultclientConfigimpl.default_max_auto_retries_next_server); RIBBONTIMEOUT = (RIBBONREADTIMEOUT + RIBBONCONNECTTIMEOUT) * (MAXAUTORETRIES + 1) * (MAXAutorEretiesNextServer + 1); } return 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 () + "." + Property, config.get (configkey, defaultValue)). get (); } @Deprecated // todo удален в 2.0.x защищенный статический сеттер getSetter (окончательная строка CommandKey, ZuulProperties ZuulProperties) {return getSetter (CommandKey, ZuulProperties, null); } Защищенный статический сеттер GetSetter (Final String CommandKey, ZuulProperties ZuulProperties, iClientConfig Config) {// @formatter: Off Setter CommandSetter = setter.WithGroupKey (hystrixCommandGroupkey.Askey.Askey ("ribboncommand"). final hystrixcommandproperties.setter setter = createSetter (config, commandkey, ZuulProperties); if (zuulproperties.getRibbonisolationStrategy () == executioSolationStrategy.semaphore) {final String name = zuulconstants.zuul_eureka + commandkey + ".semaphore.maxsemaphores"; // Мы хотим по умолчанию в семифор-изоляции, так как это обворачивает // 2 других команд, которые уже представляют собой отдельные потоки, конечный динамический центр setter.withexecutionisolationsemaphoremaxconcurrentrequests (value.get ()); } else if (zuulproperties.getThreadPool (). IsusEseParateThreadPools ()) {final String ThreatPoolKey = ZuulProperties.getThreadPool (). getThreadPoolKeyPrefix () + CommandKey; CommandSetter.andThreadPoolKey (hystrixThreadPoolkey.factory.askey (ThreadPoolKey)); } return CommandSetter.andCommandPropertiesDefaults (setter); // @formatter: on} @Override защищенное клиент. RQ запрос = createrequest (); Ответ RS; boolean retryableclient = this.client экземпляр AbstractloadlanceClient && ((AbstractLoadBalanceClient) this.Client) .isclientRetryable ((ContextAwarerEquest) запрос); if (retryableclient) {response = this.client.execute (request, config); } else {response = this.client.executewithloadbalancer (request, config); } context.set ("ribbonresponse", response); // Явно закройте HTTPResponse, если команда Hystrix приехала, чтобы // выпустить базовое соединение HTTP, которое хранится в соответствии с ответом. // if (this.isresponsetimedout ()) {if (response! = null) {response.close (); }} вернуть новую ленточную ленту (ответ); } @Override Protected Clienthttpresponse getFallback () {if (ZuulfallbackProvider! = Null) {return getFallbackResponse (); } return super.getFallback (); } защищенный клиент. причина = причина == null? GetExecutionException (): причина; if (причина == null) {zuulfallbackprovider.fallbackresponse (); } else {return (((SwarkbackProvider) zuulfallbackprovider) .fallbackresponse (canes); }} return zuulfallbackprovider.fallbackresponse (); } public lbc getClient () {return Client; } public RibbonCommandContext getContext () {return Context; } защищенный абстрактный RQ CreaterEquest () бросает исключение;}Обратите внимание: метод GetRibBontimeout и метод GethystrixTimeout, где значение этих двух методов является названием маршрута. Например, если мы посещаем: http: // localhost: 8088/order-server/xxx для доступа к службе заказа и сервера, тогда Commandkey-это заказ-сервер
Согласно исходному коду, мы сначала установили параметры тайм-аута шлюза:
#Global лента Настройки ленты: ConnectTimeout: 3000 readtimeout: 3000HyStrix: Команда: По умолчанию: выполнение: Изоляция: Поток: TimeOutInmilliseconds: 3000zuul: Host: ConnectTimeOutmillis: 10000
Конечно, вы также можете установить параметры тайм-аута ленты для порядок-сервер отдельно: order-server.ribbon.xxxx = xxx. Чтобы продемонстрировать резервный эффект в Zuul, я установил тайм -аут Hystrix немного короче. Конечно, лучше не устанавливать тайм -аут Hystrix по умолчанию, чтобы быть короче тайм -аута ленты. Эта ситуация была предупреждена о нас в исходном коде.
Затем мы добавляем следующий метод в соответствии с заказом:
@Getmapping ("/sleep/{sleeptime}") public String Sleep (@pathvarible long sleeptime) throws treampteDexception {timeUnit.seconds.sele (Sleeptime); вернуть "успех"; }2. Метод отступления Зуула
Мы можем реализовать интерфейс 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.route.zuulfallaflbekprever. org.springframework.http.httpheaders; import org.springframework.http.httpstatus; import org.springframework.http.mediatype; импорт org.spramework.http.clienthttprespons; java.io.bytearrayinputstream; import java.io.ioexception; import java.io.inputstream; import java.time.localdateTime; импорт java.time.localtim возвращаться "*"; } @Override public clienthttpresponse fallbackresponse () {return new clienthttpresponse () {@Override public httpstatus getStatuscode () бросает ioException {return httpstatus.ok; } @Override public int getRawStatuscode () бросает ioException {return 200; } @Override public String getStatustext () бросает ioException {return "ok"; } @Override public void cloid () {} @Override public inputStream getBody () бросает ioException {string result = new gsonbuilder (). Create (). Tojson (immutablemap.of ("errorcode", 500, "content", "запрос", "время", localdateTime.now ()); вернуть новый 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.