filters

org/springframework/cloud/netflix/zuul/filters/

pre

filter type order desc
ServletDetectionFilter pre -3 Detects whether a request is ran through the {@link DispatcherServlet} or {@link ZuulServlet}.The purpose was to detect this up-front at the very beginning of Zuul filter processing and rely on this information in all filters.RequestContext is used such that the information is accessible to classes which do not have a request reference.
Servlet30WrapperFilter pre -2 zuul适配servlet request
FormBodyWrapperFilter pre -1 将上下文中ZuulRequestHeaders的content-type设置成了带文件类型+boundary的形式.
DebugFilter pre 1 debug路由标识
PreDecorationFilter pre 5 补充头信息,比如是有路由配置的,则添加proxy标识为路由id,对于非http,https以及不是forward的标识serviceId

post

filter type order desc
SendErrorFilter post 0 当上下文内含error.status_code且没经过本filter时生效,补充上下文内error信息
SendResponseFilter post 1000 返回内容

route

filter type order desc
RibbonRoutingFilter route 10 在上下文中没有routeHost且sendZuulResponse为true,而且serviceId值不为空时生效.
SimpleHostRoutingFilter route 100 在上下文中存在routeHost且sendZuulResponse为true时生效
SendForwardFilter route 500 存在forward.to以及sendForwardFilter.ran为false时生效

PreDecorationFilter填充上下文变量

spring-cloud-netflix-core-1.2.6.RELEASE-sources.jar!/org/springframework/cloud/netflix/zuul/filters/pre/PreDecorationFilter.java

public class PreDecorationFilter extends ZuulFilter {

    public static final int FILTER_ORDER = 5;

    private RouteLocator routeLocator;

    private String dispatcherServletPath;

    private ZuulProperties properties;

    private UrlPathHelper urlPathHelper = new UrlPathHelper();

    private ProxyRequestHelper proxyRequestHelper;

    public PreDecorationFilter(RouteLocator routeLocator, String dispatcherServletPath, ZuulProperties properties,
            ProxyRequestHelper proxyRequestHelper) {
        this.routeLocator = routeLocator;
        this.properties = properties;
        this.urlPathHelper.setRemoveSemicolonContent(properties.isRemoveSemicolonContent());
        this.dispatcherServletPath = dispatcherServletPath;
        this.proxyRequestHelper = proxyRequestHelper;
    }

    @Override
    public int filterOrder() {
        return FILTER_ORDER;
    }

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        return !ctx.containsKey("forward.to") // a filter has already forwarded
                && !ctx.containsKey("serviceId"); // a filter has already determined
                                                    // serviceId
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        final String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest());
        Route route = this.routeLocator.getMatchingRoute(requestURI);
        if (route != null) {
            String location = route.getLocation();
            if (location != null) {
                ctx.put("requestURI", route.getPath());
                ctx.put("proxy", route.getId());
                if (!route.isCustomSensitiveHeaders()) {
                    this.proxyRequestHelper
                            .addIgnoredHeaders(this.properties.getSensitiveHeaders().toArray(new String[0]));
                }
                else {
                    this.proxyRequestHelper.addIgnoredHeaders(route.getSensitiveHeaders().toArray(new String[0]));
                }

                if (route.getRetryable() != null) {
                    ctx.put("retryable", route.getRetryable());
                }

                if (location.startsWith("http:") || location.startsWith("https:")) {
                    ctx.setRouteHost(getUrl(location));
                    ctx.addOriginResponseHeader("X-Zuul-Service", location);
                }
                else if (location.startsWith("forward:")) {
                    ctx.set("forward.to",
                            StringUtils.cleanPath(location.substring("forward:".length()) + route.getPath()));
                    ctx.setRouteHost(null);
                    return null;
                }
                else {
                    // set serviceId for use in filters.route.RibbonRequest
                    ctx.set("serviceId", location);
                    ctx.setRouteHost(null);
                    ctx.addOriginResponseHeader("X-Zuul-ServiceId", location);
                }
                if (this.properties.isAddProxyHeaders()) {
                    addProxyHeaders(ctx, route);
                    String xforwardedfor = ctx.getRequest().getHeader("X-Forwarded-For");
                    String remoteAddr = ctx.getRequest().getRemoteAddr();
                    if (xforwardedfor == null) {
                        xforwardedfor = remoteAddr;
                    }
                    else if (!xforwardedfor.contains(remoteAddr)) { // Prevent duplicates
                        xforwardedfor += ", " + remoteAddr;
                    }
                    ctx.addZuulRequestHeader("X-Forwarded-For", xforwardedfor);
                }
                if (this.properties.isAddHostHeader()) {
                    ctx.addZuulRequestHeader("Host", toHostHeader(ctx.getRequest()));
                }
            }
        }
        else {
            log.warn("No route found for uri: " + requestURI);

            String fallBackUri = requestURI;
            String fallbackPrefix = this.dispatcherServletPath; // default fallback
                                                                // servlet is
                                                                // DispatcherServlet

            if (RequestUtils.isZuulServletRequest()) {
                // remove the Zuul servletPath from the requestUri
                log.debug("zuulServletPath=" + this.properties.getServletPath());
                fallBackUri = fallBackUri.replaceFirst(this.properties.getServletPath(), "");
                log.debug("Replaced Zuul servlet path:" + fallBackUri);
            }
            else {
                // remove the DispatcherServlet servletPath from the requestUri
                log.debug("dispatcherServletPath=" + this.dispatcherServletPath);
                fallBackUri = fallBackUri.replaceFirst(this.dispatcherServletPath, "");
                log.debug("Replaced DispatcherServlet servlet path:" + fallBackUri);
            }
            if (!fallBackUri.startsWith("/")) {
                fallBackUri = "/" + fallBackUri;
            }
            String forwardURI = fallbackPrefix + fallBackUri;
            forwardURI = forwardURI.replaceAll("//", "/");
            ctx.set("forward.to", forwardURI);
        }
        return null;
    }

    private void addProxyHeaders(RequestContext ctx, Route route) {
        HttpServletRequest request = ctx.getRequest();
        String host = toHostHeader(request);
        String port = String.valueOf(request.getServerPort());
        String proto = request.getScheme();
        if (hasHeader(request, "X-Forwarded-Host")) {
            host = request.getHeader("X-Forwarded-Host") + "," + host;
            if (!hasHeader(request, "X-Forwarded-Port")) {
                if (hasHeader(request, "X-Forwarded-Proto")) {
                    StringBuilder builder = new StringBuilder();
                    for (String previous : StringUtils.commaDelimitedListToStringArray(request.getHeader("X-Forwarded-Proto"))) {
                        if (builder.length()>0) {
                            builder.append(",");
                        }
                        builder.append("https".equals(previous) ? "443" : "80");
                    }
                    builder.append(",").append(port);
                    port = builder.toString();
                }
            } else {
                port = request.getHeader("X-Forwarded-Port") + "," + port;
            }
            proto = request.getHeader("X-Forwarded-Proto") + "," + proto;
        }
        ctx.addZuulRequestHeader("X-Forwarded-Host", host);
        ctx.addZuulRequestHeader("X-Forwarded-Port", port);
        ctx.addZuulRequestHeader(ZuulHeaders.X_FORWARDED_PROTO, proto);
        addProxyPrefix(ctx, route);
    }

    private boolean hasHeader(HttpServletRequest request, String name) {
        return StringUtils.hasLength(request.getHeader(name));
    }

    private void addProxyPrefix(RequestContext ctx, Route route) {
        String forwardedPrefix = ctx.getRequest().getHeader("X-Forwarded-Prefix");
        String contextPath = ctx.getRequest().getContextPath();
        String prefix = StringUtils.hasLength(forwardedPrefix) ? forwardedPrefix
                : (StringUtils.hasLength(contextPath) ? contextPath : null);
        if (StringUtils.hasText(route.getPrefix())) {
            StringBuilder newPrefixBuilder = new StringBuilder();
            if (prefix != null) {
                if (prefix.endsWith("/") && route.getPrefix().startsWith("/")) {
                    newPrefixBuilder.append(prefix, 0, prefix.length() - 1);
                }
                else {
                    newPrefixBuilder.append(prefix);
                }
            }
            newPrefixBuilder.append(route.getPrefix());
            prefix = newPrefixBuilder.toString();
        }
        if (prefix != null) {
            ctx.addZuulRequestHeader("X-Forwarded-Prefix", prefix);
        }
    }

    private String toHostHeader(HttpServletRequest request) {
        int port = request.getServerPort();
        if ((port == 80 && "http".equals(request.getScheme()))
                || (port == 443 && "https".equals(request.getScheme()))) {
            return request.getServerName();
        }
        else {
            return request.getServerName() + ":" + port;
        }
    }

    private URL getUrl(String target) {
        try {
            return new URL(target);
        }
        catch (MalformedURLException ex) {
            throw new IllegalStateException("Target URL is malformed", ex);
        }
    }
}

doc


想获取最新内容,请关注微信公众号

图片描述


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...