聊聊spring cloud gateway的SetStatusGatewayFilter

本文主要研究下spring cloud gateway的SetStatusGatewayFilterhtml

GatewayAutoConfiguration

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.javajava

@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {
    //......
	@Bean
	public SetStatusGatewayFilterFactory setStatusGatewayFilterFactory() {
		return new SetStatusGatewayFilterFactory();
	}
    //......
}

默認建立SetStatusGatewayFilterFactoryspring

SetStatusGatewayFilterFactory

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.javaapp

public class SetStatusGatewayFilterFactory extends AbstractGatewayFilterFactory<SetStatusGatewayFilterFactory.Config> {

	public static final String STATUS_KEY = "status";

	public SetStatusGatewayFilterFactory() {
		super(Config.class);
	}

	@Override
	public List<String> shortcutFieldOrder() {
		return Arrays.asList(STATUS_KEY);
	}

	@Override
	public GatewayFilter apply(Config config) {
		final HttpStatus status = ServerWebExchangeUtils.parse(config.status);
		final Integer intStatus;
		if (status == null) {
			intStatus = Integer.parseInt(config.status);
		} else {
			intStatus = null;
		}
		return (exchange, chain) -> {

			// option 1 (runs in filter order)
			/*exchange.getResponse().beforeCommit(() -> {
				exchange.getResponse().setStatusCode(finalStatus);
				return Mono.empty();
			});
			return chain.filter(exchange);*/

			// option 2 (runs in reverse filter order)
			return chain.filter(exchange).then(Mono.fromRunnable(() -> {
				// check not really needed, since it is guarded in setStatusCode,
				// but it's a good example
				if (!exchange.getResponse().isCommitted()) {
					if (status != null) { // standard status
						setResponseStatus(exchange, status);
					} else if (intStatus != null && exchange.getResponse() instanceof AbstractServerHttpResponse) { //non-standard
						((AbstractServerHttpResponse)exchange.getResponse()).setStatusCodeValue(intStatus);
					}
				}
			}));
		};
	}

	public static class Config {
		//TODO: relaxed HttpStatus converter
		private String status;

		public String getStatus() {
			return status;
		}

		public void setStatus(String status) {
			this.status = status;
		}
	}

}
  • 能夠看到,就是簡單地根據status來設置response的status
  • 注意這裏有兩個option,源碼註釋掉了option1,改成使用option2

實例

spring:
  cloud:
    gateway:
      routes:
      - id: setstatusstring_route
        uri: http://example.org
        predicates:
        - Path=/foo/**
        filters:
        - SetStatus=BAD_REQUEST
      - id: setstatusint_route
        uri: http://example.org
        predicates:
        - Path=/name/**
        filters:
        - SetStatus=401

小結

SetStatusGatewayFilter就是簡單地設置response,使用option1方式的話,是在response commit以前設置的,並且一旦設置就直接return,再也不繼續走filter了,於是SetStatus能夠生效;使用option2的話,是逆filter順序執行的,會先判斷是否commit,未commit才設置,實際不生效。ide

doc

相關文章
相關標籤/搜索