gateway 網關(轉發,跨域,攔截器等)


1,所需依賴

<!-- 網關依賴 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

2,配置路徑映射

spring:
  cloud:
    gateway:
      discovery:
        locator:
          # 開啟項目名稱映射功能,即通過服務名訪問項目,不需要寫明具體IP地址
          enabled: true
          # 請求路由全部轉小寫字母,如 Aa/Bb 會被轉為 aa/bb
          lower-case-service-id: true
      routes:
          # 路由規則的唯一標識,任意齊名,建議和服務名一致
        - id: sc-web-admin-back
          # 轉發到的節點,lb:// 為 http,lb:ws:// 為 websocket
          uri: lb://sc-web-admin-back/
          predicates:
              # 斷言規則,這里設置匹配的路由規則
            - Path=/admin-back/**
          # 過濾規則
          filters:
            # 轉發到具體項目去掉路由首單詞,如 /admin-back/a 轉發為 /a
            - StripPrefix=1

如上,便配置了一個接管以 admin-back 開頭的路由,並轉發給項目 sc-web-admin-back

3,跨域配置

spring:
  cloud:
    gateway:
      globalcors:
        # 全局允許跨域訪問
        cors-configurations:
          '[/**]':
            allow-credentials: true
            allowed-origins: "*"
            allowed-headers: "*"
            allowed-methods:
              - OPTIONS
              - GET
              - POST
              - PUT
              - DELETE

4,全局異常處理

日常開發中,我們難免會有忘記處理的異常,程序也很難保重不出錯,這時候我們就需要一個能夠全局捕捉異常的功能來未我們兜底,防止錯誤被用戶看到影響體驗

package com.hwq.gateway.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hwq.gateway.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;

@Component
@Primary   // 同類型帶有該注解的 Bean 優先背識別
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class JsonExceptionHandler implements WebExceptionHandler {

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 所有異常都會在這里被集中處理
     * @param exchange 上下文
     * @param ex       異常
     * SuppressWarnings("NullableProblems"):屏蔽 @NonNullApi 的警告
     */
    @Override
    @SuppressWarnings("NullableProblems")
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        ResultVO<Object> vo;
        if (ex instanceof ResponseStatusException && ((ResponseStatusException) ex).getStatus() == HttpStatus.NOT_FOUND) {
            vo = ResultVO.fail("當前訪問的地址不存在,請修改后重試!");
        } else {
            vo = ResultVO.error(ex.getMessage());
        }
        return response.writeWith(Mono.fromSupplier(() -> {
            byte[] bytes;
            try {
                bytes = objectMapper.writeValueAsBytes(vo);
            } catch (JsonProcessingException e) {
                response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                bytes = "JSON 轉換異常!".getBytes();
            }
            return response.bufferFactory().wrap(bytes);
        }));
    }

}

5,捕獲轉發項目傳來的異常

上面的類只能捕捉網關本身發生的異常,而如果其調用(轉發)的項目發生異常,返回錯誤時不能攔截,這時候我們就需要一個過濾器,能把哪些錯誤的返回攔截掉,並觸發上面全局異常處理

package com.hwq.gateway.filter;

import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

@Component
public class ExceptionFilter implements Ordered, GlobalFilter {

    /**
     * 如果需要攔截返回值並處理,這里則需要返回負數
     */
    @Override
    public int getOrder() {
        return -1;
    }

    /**
     * 異常攔截,攔截響應值不是 200 的數據,並拋給全局異常處理
     */
    @Override
    @SuppressWarnings({"unchecked", "NullableProblems"})
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpResponseDecorator decorated = new ServerHttpResponseDecorator(response) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.map(dataBuffer -> {
                        if (response.getStatusCode() == HttpStatus.NOT_FOUND) {
                            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
                        }
                        if (response.getStatusCode() != HttpStatus.OK) {
                            byte[] content = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(content);
                            DataBufferUtils.release(dataBuffer); // 釋放掉內存
                            String errMsg = new String(content, StandardCharsets.UTF_8);
                            throw new RuntimeException(errMsg);
                        }
                        return dataBuffer;
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decorated).build());
    }

}

6,普通的過濾器

package com.hwq.gateway.filter;

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.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class UserFilter implements Ordered, GlobalFilter {

    /**
     * 這里的返回值決定攔截器的優先級,數字越小越先被觸發,支持負數
     */
    @Override
    public int getOrder() {
        return 1;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 這里可以獲取 請求對象 和 響應對象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        // 邏輯處理
        

        // 邏輯處理

        // 傳遞給下一級別的過濾器
        return chain.filter(exchange);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM