Spring cloud gateway 拦截请求404 等HTTP 状态码

              Spring cloud gateway 处理跨域问题

               Spring cloud gateway 设置https 和http同时支持

              Spring cloud gateway 修改response 截断问题,乱码问题解决

              Spring cloud gateway 详解和配置使用(文章较长) 

              Spring cloud Gateway 指定执行过滤器 (在配置文件中配置所需要过滤器)

不废话

可以直接debug 一步一步跟

或者直接拿

AbstractErrorWebExceptionHandler 找到这个class 拿出来

并创建一个 一模一样的包放到里面, 因为是就近原则所有会走后提出来的文件

org.springframework.boot.autoconfigure.web.reactive.error

 在handle 方法中进行添加状态的拦截校验,朋友们可以根据自己需求进行添加修改,

完整类

package org.springframework.boot.autoconfigure.web.reactive.error;/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.logging.Log;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpLogging;
import org.springframework.http.HttpStatus;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.HtmlUtils;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * Abstract base class for {@link ErrorWebExceptionHandler} implementations.
 *
 * @author Brian Clozel
 * @since 2.0.0
 * @see ErrorAttributes
 */
@Slf4j
public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExceptionHandler, InitializingBean {

	/**
	 * Currently duplicated from Spring WebFlux HttpWebHandlerAdapter.
	 */
	private static final Set<String> DISCONNECTED_CLIENT_EXCEPTIONS;

	static {
		Set<String> exceptions = new HashSet<>();
		exceptions.add("AbortedException");
		exceptions.add("ClientAbortException");
		exceptions.add("EOFException");
		exceptions.add("EofException");
		DISCONNECTED_CLIENT_EXCEPTIONS = Collections.unmodifiableSet(exceptions);
	}

	private static final Log logger = HttpLogging.forLogName(org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler.class);

	private final ApplicationContext applicationContext;

	private final ErrorAttributes errorAttributes;

	private final ResourceProperties resourceProperties;

	private final TemplateAvailabilityProviders templateAvailabilityProviders;

	private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();

	private List<HttpMessageWriter<?>> messageWriters = Collections.emptyList();

	private List<ViewResolver> viewResolvers = Collections.emptyList();

	public AbstractErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
                                            ApplicationContext applicationContext) {
		Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
		Assert.notNull(resourceProperties, "ResourceProperties must not be null");
		Assert.notNull(applicationContext, "ApplicationContext must not be null");
		this.errorAttributes = errorAttributes;
		this.resourceProperties = resourceProperties;
		this.applicationContext = applicationContext;
		this.templateAvailabilityProviders = new TemplateAvailabilityProviders(applicationContext);
	}

	/**
	 * Configure HTTP message writers to serialize the response body with.
	 * @param messageWriters the {@link HttpMessageWriter}s to use
	 */
	public void setMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
		Assert.notNull(messageWriters, "'messageWriters' must not be null");
		this.messageWriters = messageWriters;
	}

	/**
	 * Configure HTTP message readers to deserialize the request body with.
	 * @param messageReaders the {@link HttpMessageReader}s to use
	 */
	public void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {
		Assert.notNull(messageReaders, "'messageReaders' must not be null");
		this.messageReaders = messageReaders;
	}

	/**
	 * Configure the {@link ViewResolver} to use for rendering views.
	 * @param viewResolvers the list of {@link ViewResolver}s to use
	 */
	public void setViewResolvers(List<ViewResolver> viewResolvers) {
		this.viewResolvers = viewResolvers;
	}

	/**
	 * Extract the error attributes from the current request, to be used to populate error
	 * views or JSON payloads.
	 * @param request the source request
	 * @param includeStackTrace whether to include the error stacktrace information
	 * @return the error attributes as a Map.
	 */
	protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
		return this.errorAttributes.getErrorAttributes(request, includeStackTrace);
	}

	/**
	 * Extract the original error from the current request.
	 * @param request the source request
	 * @return the error
	 */
	protected Throwable getError(ServerRequest request) {
		return this.errorAttributes.getError(request);
	}

	/**
	 * Check whether the trace attribute has been set on the given request.
	 * @param request the source request
	 * @return {@code true} if the error trace has been requested, {@code false} otherwise
	 */
	protected boolean isTraceEnabled(ServerRequest request) {
		String parameter = request.queryParam("trace").orElse("false");
		return !"false".equalsIgnoreCase(parameter);
	}

	/**
	 * Render the given error data as a view, using a template view if available or a
	 * static HTML file if available otherwise. This will return an empty
	 * {@code Publisher} if none of the above are available.
	 * @param viewName the view name
	 * @param responseBody the error response being built
	 * @param error the error data as a map
	 * @return a Publisher of the {@link ServerResponse}
	 */
	protected Mono<ServerResponse> renderErrorView(String viewName, ServerResponse.BodyBuilder responseBody,
			Map<String, Object> error) {
		if (isTemplateAvailable(viewName)) {
			return responseBody.render(viewName, error);
		}
		Resource resource = resolveResource(viewName);
		if (resource != null) {
			return responseBody.body(BodyInserters.fromResource(resource));
		}
		return Mono.empty();
	}

	private boolean isTemplateAvailable(String viewName) {
		return this.templateAvailabilityProviders.getProvider(viewName, this.applicationContext) != null;
	}

	private Resource resolveResource(String viewName) {
		for (String location : this.resourceProperties.getStaticLocations()) {
			try {
				Resource resource = this.applicationContext.getResource(location);
				resource = resource.createRelative(viewName + ".html");
				if (resource.exists()) {
					return resource;
				}
			}
			catch (Exception ex) {
				// Ignore
			}
		}
		return null;
	}

	/**
	 * Render a default HTML "Whitelabel Error Page".
	 * <p>
	 * Useful when no other error view is available in the application.
	 * @param responseBody the error response being built
	 * @param error the error data as a map
	 * @return a Publisher of the {@link ServerResponse}
	 */
	protected Mono<ServerResponse> renderDefaultErrorView(ServerResponse.BodyBuilder responseBody,
			Map<String, Object> error) {
		StringBuilder builder = new StringBuilder();
		Date timestamp = (Date) error.get("timestamp");
		Object message = error.get("message");
		Object trace = error.get("trace");
		builder.append("<html><body><h1>Whitelabel Error Page</h1>")
				.append("<p>This application has no configured error view, so you are seeing this as a fallback.</p>")
				.append("<div id='created'>").append(timestamp).append("</div>")
				.append("<div>There was an unexpected error (type=").append(htmlEscape(error.get("error")))
				.append(", status=").append(htmlEscape(error.get("status"))).append(").</div>");
		if (message != null) {
			builder.append("<div>").append(htmlEscape(message)).append("</div>");
		}
		if (trace != null) {
			builder.append("<div style='white-space:pre-wrap;'>").append(htmlEscape(trace)).append("</div>");
		}
		builder.append("</body></html>");
		return responseBody.syncBody(builder.toString());
	}

	private String htmlEscape(Object input) {
		return (input != null) ? HtmlUtils.htmlEscape(input.toString()) : null;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if (CollectionUtils.isEmpty(this.messageWriters)) {
			throw new IllegalArgumentException("Property 'messageWriters' is required");
		}
	}

	/**
	 * Create a {@link RouterFunction} that can route and handle errors as JSON responses
	 * or HTML views.
	 * <p>
	 * If the returned {@link RouterFunction} doesn't route to a {@code HandlerFunction},
	 * the original exception is propagated in the pipeline and can be processed by other
	 * {@link org.springframework.web.server.WebExceptionHandler}s.
	 * @param errorAttributes the {@code ErrorAttributes} instance to use to extract error
	 * information
	 * @return a {@link RouterFunction} that routes and handles errors
	 */
	protected abstract RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes);

	@Override
	public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
		if (exchange.getResponse().isCommitted() || isDisconnectedClientError(throwable)) {
			return Mono.error(throwable);
		}
		this.errorAttributes.storeErrorInformation(throwable, exchange);
		ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
        if (throwable instanceof ResponseStatusException){
            HttpStatus status = ((ResponseStatusException) throwable).getStatus();
            if (HttpStatus.NOT_FOUND.equals(status)) {
              // TODO 处理你自己的业务
              // TODO 处理你自己的业务
            }
        }
        return getRoutingFunction(this.errorAttributes).route(request).switchIfEmpty(Mono.error(throwable))
				.flatMap((handler) -> handler.handle(request))
				.doOnNext((response) -> logError(request, response, throwable))
				.flatMap((response) -> write(exchange, response));
	}

	private boolean isDisconnectedClientError(Throwable ex) {
		return DISCONNECTED_CLIENT_EXCEPTIONS.contains(ex.getClass().getSimpleName())
				|| isDisconnectedClientErrorMessage(NestedExceptionUtils.getMostSpecificCause(ex).getMessage());
	}

	private boolean isDisconnectedClientErrorMessage(String message) {
		message = (message != null) ? message.toLowerCase() : "";
		return (message.contains("broken pipe") || message.contains("connection reset by peer"));
	}

	private void logError(ServerRequest request, ServerResponse response, Throwable throwable) {
		if (logger.isDebugEnabled()) {
			logger.debug(request.exchange().getLogPrefix() + formatError(throwable, request));
		}
		if (response.statusCode().equals(HttpStatus.INTERNAL_SERVER_ERROR)) {
			logger.error(request.exchange().getLogPrefix() + "500 Server Error for " + formatRequest(request),
					throwable);
		}
	}

	private String formatError(Throwable ex, ServerRequest request) {
		String reason = ex.getClass().getSimpleName() + ": " + ex.getMessage();
		return "Resolved [" + reason + "] for HTTP " + request.methodName() + " " + request.path();
	}

	private String formatRequest(ServerRequest request) {
		String rawQuery = request.uri().getRawQuery();
		String query = StringUtils.hasText(rawQuery) ? "?" + rawQuery : "";
		return "HTTP " + request.methodName() + " \"" + request.path() + query + "\"";
	}

	private Mono<? extends Void> write(ServerWebExchange exchange, ServerResponse response) {
		// force content-type since writeTo won't overwrite response header values
		exchange.getResponse().getHeaders().setContentType(response.headers().getContentType());
		return response.writeTo(exchange, new ResponseContext());
	}

	private class ResponseContext implements ServerResponse.Context {

		@Override
		public List<HttpMessageWriter<?>> messageWriters() {
			return org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler.this.messageWriters;
		}

		@Override
		public List<ViewResolver> viewResolvers() {
			return org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler.this.viewResolvers;
		}

	}

}

 

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Spring Cloud Gateway 中,你可以使用 GlobalFilter 和 GatewayFilter 来拦截请求的前后方法。GlobalFilter 是在全局范围内拦截请求的过滤器,而 GatewayFilter 是在特定路由下拦截请求的过滤器。 下面是一个示例,演示如何在 Spring Cloud Gateway拦截请求的前后方法: 1. 创建一个实现 GlobalFilter 接口的自定义全局过滤器: ```java import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class CustomGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); // 在请求前进行拦截的逻辑 // 可以修改请求头、添加认证信息等 return chain.filter(exchange).then(Mono.fromRunnable(() -> { // 在请求后进行拦截的逻辑 // 可以对响应进行处理、错误处理等 })); } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; // 设置过滤器的优先级 } } ``` 2. 创建一个实现 GatewayFilter 接口的自定义路由过滤器: ```java import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class CustomGatewayFilter implements GatewayFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 在请求前进行拦截的逻辑 // 可以修改请求头、添加认证信息等 return chain.filter(exchange).then(Mono.fromRunnable(() -> { // 在请求后进行拦截的逻辑 // 可以对响应进行处理、错误处理等 })); } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; // 设置过滤器的优先级 } } ``` 在上述代码中,CustomGlobalFilter 是一个自定义的全局过滤器,实现了 GlobalFilter 接口。CustomGatewayFilter 是一个自定义的路由过滤器,实现了 GatewayFilter 接口。你可以根据实际需求在相应的方法中编写自己的拦截逻辑。 这些过滤器会被自动注册到 Spring Cloud Gateway 中,并在请求经过时进行拦截。你可以在过滤器中对请求进行修改、添加认证信息等操作,并对响应进行处理或错误处理。 注意:上述代码片段仅为示例,你需要根据自己的业务需求进行适当的调整和配置。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值