春の雲(7):サービス・ゲートウェイzuulフィルタ

Zuulフィルタ(フィルタ) - ルーティング機能Zuul紙上記の基本的な使用は、その後、コアコンセプトZuulを導入します。

Zuul基本的な機能は、異なる段階で、Zuulフィルタによって(責任のパターンの支柱インターセプター使用鎖以外、ZuulをFilterProcessorにより実行制御される支柱インターセプタに類似)フィルタの異なる種類によって実現を実現しました対応する機能。

Zuulフィルタ

フィルタタイプ

HTTPリクエストの処理段階に応じて4種類含むzuulフィルタ

  • プリ:そう、一般的に認証を要求するため、バックエンドサービスの実行対象に要求を転送するルーティングアドレスを決定、ロギング、および前
  • ルートは:ターゲット・サービスのための構築物またはリボン要求にはApacheのHttpClientを使用して、要求を転送します
  • ポスト:ターゲット・サービスは、統計的パフォーマンスデータを収集するための応答ヘッダを追加するように、処理結果に結果を返した後
  • Error:エラーが発生した場合、要求を処理するプロセス全体は、エラー処理のため実行エラーフィルタをトリガーします

以下のフィルタ処理の流れを経てZuulクライアント要求

Zuulフィルタ

zuulを用いるRequestContextフィルタとの間でデータを渡すために、ルート要求、エラー、のHttpServletRequest、HttpServletResponseのに他のそのようなデータはRequestContextの中に格納されている場合を含む各要求のThreadLocalに格納されたデータ、。私たちは、コンテキストに渡された情報を保持する必要がある場合がありますので、RequestContextには、ConcurrentHashMapのを拡大しました。

@EnableZuulServer対@EnableZuulProxy

zuul提供了两个注解 @EnableZuulProxy, @EnableZuulServer,来启用不同的过滤器集合。@EnableZuulProxy 启用的过滤器 是@EnableZuulServer 的超集, 它包含了@EnableZuulServer 的所有过滤器,proxy主要多了一些提供路由功能的过滤器(可见@EnableZuulServer 不提供路由功能,作为server模式而不是代理模式运行)

@EnableZuulServer 注解启用的过滤器包括

filter类型 实现类 filter顺序值 功能说明
pre ServletDetectionFilter -3 检测请求是否通过Spring Dispatcher,并在RequestContext 中添加一个key为isDispatcherServletRequest, 值为true(不通过则为false)的属性
pre FormBodyWrapperFilter -1 解析Form data,为请求的下游进行重新编码
pre DebugFilter 1 如果请求参数设置了debug,则会将RequestContext.setDebugRouting() ,RequestContext.setDebugRequest() 设置为ture
route SendForwardFilter 500 使用RequestDispatch servlet来转发请求,转发地址存于RequestContext中key为FilterConstants.FORWARD_TO_KEY的属性中,对于转发到当前应用的接口比较有用
post SendResponseFilter 1000 将代理请求的响应内容写到当前的响应中
error SendErrorFilter 0 如果RequestContext.getThrowable() 不为空,则会转发到/error,可以通过error.path来改变默认的转发路径/error

@EnableZuulProxy 除了上面的过滤器,还包含如下过滤器

filter类型 实现类 filter顺序值 功能说明
pre PreDecorationFilter 5 确定路由到哪里,如何路由,依赖提供的RouteLocator,同时也为下游请求设置多个与proxy相关的header
route RibbonRoutingFilter 10 使用ribbon,hystrix,以及内嵌的http client来发送请求,可在RequestContext中通过FilterConstants.SERVICE_ID_KEY 来找到路由Service的ID
route SimpleHostRoutingFilter 100 使用Apache httpClient来发送请求到一个预先确定的url,可通过RequestContext.getRouteHost()来获取urls

由上可见@EnableZuulServer 注解并不包含往后端服务负载均衡地路由请求的代理功能,@EnableZuulProxy的PreDecorationFilter,RibbonRoutingFilter过滤器才能担当此任。PreDecorationFilter通过提供的DiscoveryClientRouteLocator 从 DiscoveryClient(如Eureka)与属性文件中加载路由定义, 为每个serviceId创建一个route,新服务添加进来,路由也会动态刷新。路由确定了,在RibbonRoutingFilter 中通过ribbon与hystrix结合来向后端目标服务发起请求,并进行负载均衡。过滤器的顺序值表示在同类型过滤器中的执行顺序,值越小越先执行。

自定义Zuul过滤器

自定义的zuul过滤器与框架自带过滤器类似,包括四部分

  1. 过滤器类型,包括pre, route, post
  2. 过滤器顺序,定义在同类型过滤器中的执行顺序,数值越小越先执行
  3. 是否执行过滤,通过一些条件判断来确定是否执行该过滤器
  4. 过滤器执行体,定义具体执行的操作

比如我们需要在Http请求头中设置一个值,供请求链路的下游环节访问,则可以自定义一个过滤器如下,

@Component
public class ReqIdPreFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; //在PreDecorationFilter过滤器之前执行
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.addZuulRequestHeader("reqId", UUID.randomUUID().toString());
        return null;
    }
}

そのようなインターフェース又はバックエンドサービスフィルタとして要求のその後の部分では、値は、ヘッダのHttpServletRequestから取得することができる、など

@GetMapping("hello/reqId")
public String getReqId(HttpServletRequest request) {
    return "hello-service返回:" + request.getHeader("reqId");
}

Zuulエラー処理

任意の1つのリンクが例外エラーフィルタが実行されますスローライフサイクルzuulフィルタでは、RequestContext.getThrowable()が実行されませんのみSendErrorFilterがnull、セットjavax.servlet.errorです。*リクエストに属性、そして春のブート・エラー・ページに転送要求、デフォルトで/エラーBasicErrorControllerインタフェースが実装されています。時には我々は統一応答形式に戻す必要がある、との要件を満たしていない可能性があり、デフォルト/エラー・インターフェースは、あなたが/エラー・インターフェースをカスタマイズすることができます。デフォルトBasicErrorController障害ようにインターフェイスを実装するのErrorController必要。

@RestController
public class ZuulErrorController implements ErrorController {

    @RequestMapping("/error")
    public Map<String, String> error(HttpServletRequest request){
        Map<String, String> result = Maps.newHashMap();
        result.put("code", request.getAttribute("javax.servlet.error.status_code").toString());
        result.put("message", request.getAttribute("javax.servlet.error.message").toString());
        result.put("exception", request.getAttribute("javax.servlet.error.exception").toString());
        return result;
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }
}

Zuulサービス低下

タイムアウト発生した場合、または異常な通話サービスは、側zuulコールバックサービスの低下で提供することができる場合、結果は、次のようなデフォルトの応答を返します

@Component
public class MyFallbackProvider implements FallbackProvider {

    @Override
    public String getRoute() {
        return null; //指定这个回调针对的route Id,如果对所有route,则返回* 或null
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        if (cause instanceof HystrixTimeoutException) {
            return response(HttpStatus.GATEWAY_TIMEOUT);
        } else {
            return response(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    private ClientHttpResponse response(final HttpStatus status) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return status;
            }
            @Override
            public int getRawStatusCode() throws IOException {
                return status.value();
            }
            @Override
            public String getStatusText() throws IOException {
                return status.getReasonPhrase();
            }
            @Override
            public void close() {
            }
            @Override
            public InputStream getBody() throws IOException {
                Map<String, String> result = Maps.newLinkedHashMap();
                result.put("code", "" + status.value());
                String msg = HttpStatus.GATEWAY_TIMEOUT == getStatusCode() ? "请求服务超时" : "服务器内部错误";
                result.put("message", msg);
                return new ByteArrayInputStream(new ObjectMapper().writeValueAsString(result).getBytes());
            }
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

サービス要求が失敗した場合、それは統一フォーマット次の応答を返します。

{
    "code": "500",
    "message": "服务器内部错误"
}

概要

本論文では、Zuulフィルタの内容に焦点を当て、サービス呼び出しが失敗し、プロセスフィルタの異常動作を簡単に説明をダウングレードするコールバック処理中に導入されたの使用をカスタマイズします。スペースのために、我々はさらにフォローアップを探求し続ける開発プロセスのより具体的な詳細。
共有する幸せ深刻な生活、
マイクロチャネル公衆番号への歓迎の注意を:の技術スペース、空、山新宇
春ブーツ、春の雲、ドッカーおよびその他の技術的な記事を取得します
公共の二次元コード番号

おすすめ

転載: www.cnblogs.com/spec-dog/p/12340902.html