Gateway 过滤器,过滤器统一异常处理

以下内容,都很重要

以下内容,都很重要

以下内容,都很重要

请勿忽略

 

一, 配置文件

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:        #cors
          ‘[/**]‘:
            allowed-headers: "*"
            allowed-origins: "*"
            allowed-methods: "*"
#      discovery:
#        locator:
#          lower-case-service-id: true
#          enabled: true
      routes:
        - id: web-mac
          uri: lb://web-mac
          predicates:
            - Path=/web-mac/**
          filters:
            - StripPrefix=1
            - Token_Mac=true

解释:

一, cors 不多说了,跨域设置

二, discovery

这个当中的 locator.enabled 必须注释掉。

它会影响到过滤的转发功能。

三,属性

id:随便起名字

uri:lb开头,无需更改。web-mac是注册中心的application name(eruake显示大写,配置里用小写没关系)

predicates:匹配规则

filters:过滤器

在使用过滤器时,StripPrefix=1 必须!

Token_Mac 是我的过滤器,True是代表Config中是否开启。

 

二,过滤器

package com.tenyears.gateway.filter;
 
/**
 * @description :
 * @auther Tyler
 * @date 2021/8/12
 */
 
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
 
import java.util.Arrays;
import java.util.List;
 
 
@Component
public class Token_MacGatewayFilterFactory extends AbstractGatewayFilterFactory<Token_MacGatewayFilterFactory.Config> {
 
    private static final String TOKEN_HEADER="Authorization";
    private static final String TOKEN_IS_INVALID = "Token is invalid";
 
 
    public Token_MacGatewayFilterFactory() {
        super(Config.class);
    }
 
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("enabled");
    }
 
    @Override
    public GatewayFilter apply(Token_MacGatewayFilterFactory.Config config) {
        System.out.println("TokenGatewayFilterFactory begin");
        return (exchange, chain) -> {
 
            if (!config.isEnabled()) {
                return chain.filter(exchange);
            }
 
            ServerHttpRequest request = exchange.getRequest();
            
            HttpHeaders headers = request.getHeaders();
            String token = headers.getFirst(TOKEN_HEADER);
            System.out.println("token : "+token);
            if (StringUtils.isEmpty(token) ) {
                throw new RuntimeException(TOKEN_IS_INVALID);
//                response.setStatusCode(HttpStatus.UNAUTHORIZED);
//                return response.setComplete();
            }
 
            //验证token,这里举个例子
            if (!token.equals("123") ) {
                throw new RuntimeException(TOKEN_IS_INVALID);
//                response.setStatusCode(HttpStatus.UNAUTHORIZED);
//                return response.setComplete();
            }
            System.out.println("TokenGatewayFilterFactory end");
            return chain.filter(exchange);
        };
    }
 
    public static class Config {
        // 控制是否开启认证
        private boolean enabled;
 
        public Config() {}
 
        public boolean isEnabled() {
            return enabled;
        }
 
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }
 
}

一,继承自AbstractGatewayFilterFactory

二,过滤器名:Token_MacGatewayFilterFactory

必须 GatewayFilterFactory  结尾!

 

三,统一异常处理 

package com.tenyears.gateway.advice;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tenyears.model.common.ApiResult;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
 
/**
 * @description :
 * @auther Tyler
 * @date 2021/8/12
 */
 
@Order(-1)
@Configuration
public class GlobalErrorExceptionHandler implements ErrorWebExceptionHandler {
 
    private final ObjectMapper objectMapper=new ObjectMapper();
 
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        if (response.isCommitted()) {
            return Mono.error(ex);
        }
 
        // 设置返回JSON
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        if (ex instanceof ResponseStatusException) {
            response.setStatusCode(((ResponseStatusException) ex).getStatus());
        }
 
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            try {
                //返回响应结果
                ApiResult<String> result=new ApiResult<>();
                result.setCodeToFail(ex.getMessage());
                return bufferFactory.wrap(objectMapper.writeValueAsBytes(result));
            }
            catch (JsonProcessingException e) {
                return bufferFactory.wrap(new byte[0]);
            }
        }));
    }
}

 filter 抛出的异常,会被GlobalErrorExceptionHandler 统一处理

 

ApiResult<T> 

是我自定义的返回结果。 

package com.tenyears.model.common;
 
/**
 * Created by Tyler on 2017/6/20.
 */
 
@Data
public class ApiResult<T> {
    public static final String FAIL_CODE = "0";        //失败码
    public static final String SUC_CODE = "1";        //成功码
    public static final String ERROR_CODE = "2";    //错误码
    public static final String SUC_MESSAGE = "Operate successfully";    //成功信息
    public static final String FAIL_MESSAGE = "Operation failure";        //失败信息
    public static final String ERROR_MESSAGE = "System Error";            //错误信息
    public static final String NOACCESS_MESSAGE = "No permission to access this page.";        //无权操作
 
    /**
     * 代码
     * 0 失败
     * 1 成功
     * 2 错误
     * @mock 1
     */
    private String code = FAIL_CODE;
    /**
     * 信息(对应code)
     * Operate successfully
     * Operation failure
     * System Error
     * @mock Operate successfully
     */
    private String message = FAIL_MESSAGE;
    /**
     * 模型
     */
    private T data;
 
    /**
     * 当前页(分页时有效)
     */
    private Integer page_index = -1;
    /**
     * 条目(分页时有效)
     */
    private Integer page_size= -1;
 
    /**
     * 总页数(分页时有效)
     */
    private Integer total_pages=-1;
    /**
     * 总条目数(分页时有效)
     */
    private Integer total_elements=-1;
 
 
    public void setCode(String code, String message) {
        this.code = code;
        this.message = message;
    }
 
    public void setCodeToSuccessed() {
        this.code = SUC_CODE;
        this.message = SUC_MESSAGE;
    }
    public void setCodeToSuccessed(T data) {
        this.data = data;
        this.code = SUC_CODE;
        this.message = SUC_MESSAGE;
    }
    
    public void setCodeToError(String message) {
        this.code = ERROR_CODE;
        this.message = message;
    }
    
    public void setCodeToError() {
        this.code = ERROR_CODE;
        this.message = ERROR_MESSAGE;
    }
 
    public void setCodeToFail(String message) {
        this.code = ERROR_CODE;
        this.message = message;
    }
 
    public void setCodeToFail() {
        this.code = FAIL_CODE;
        this.message = FAIL_MESSAGE;
    }
    
    public void setCodeByNoAccess() {
        this.code = FAIL_CODE;
        this.message = NOACCESS_MESSAGE;
    }
 
    public boolean isSuccess() {
        return SUC_CODE.equals(code);
    }
 
}

 

Gateway 过滤器,过滤器统一异常处理

上一篇:日期格式在iphone上的兼容问题:toISOString


下一篇:泛型的受限