使用路由閘道器的全域性過濾功能

weixin_33751566發表於2019-01-16

學習完整課程請移步 網際網路 Java 全棧工程師

本節視訊

概述

全域性過濾器作用於所有的路由,不需要單獨配置,我們可以用它來實現很多統一化處理的業務需求,比如許可權認證,IP 訪問限制等等。

注意:截止部落格發表時間 2019 年 01 月 10 日,Spring Cloud Gateway 正式版為 2.0.2 其文件並不完善,並且有些地方還要重新設計,這裡僅提供一個基本的案例

詳見:Spring Cloud Gateway Documentation

宣告週期

7986413-cff8fb5e8d4a8bab.jpg

Spring Cloud Gateway 基於 Project Reactor 和 WebFlux,採用響應式程式設計風格,開啟它的 Filter 的介面 GlobalFilter 你會發現它只有一個方法 filter。

建立全域性過濾器

實現 GlobalFilter, Ordered 介面並在類上增加 @Component 註解就可以使用過濾功能了,非常簡單方便

package com.funtl.hello.spring.cloud.gateway.filters;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
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.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;

/**
 * 鑑權過濾器
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");

        if (token == null || token.isEmpty()) {
            ServerHttpResponse response = exchange.getResponse();

            // 封裝錯誤資訊
            Map<String, Object> responseData = Maps.newHashMap();
            responseData.put("code", 401);
            responseData.put("message", "非法請求");
            responseData.put("cause", "Token is empty");

            try {
                // 將資訊轉換為 JSON
                ObjectMapper objectMapper = new ObjectMapper();
                byte[] data = objectMapper.writeValueAsBytes(responseData);

                // 輸出錯誤資訊到頁面
                DataBuffer buffer = response.bufferFactory().wrap(data);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                return response.writeWith(Mono.just(buffer));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }

        return chain.filter(exchange);
    }

    /**
    * 設定過濾器的執行順序
    * @return 
    */
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

測試過濾器

瀏覽器訪問:http://localhost:9000/nacos-consumer/echo/app/name 網頁顯示

7986413-c256cdd80eff6ff4.png

瀏覽器訪問:http://localhost:9000/nacos-consumer/echo/app/name?token=123456 網頁顯示

Hello Nacos Discovery nacos-consumer i am from port 8082

附:Spring Cloud Gateway Benchmark

Spring 官方人員提供的閘道器基準測試報告 GitHub

Proxy Avg Latency Avg Req/Sec/Thread
gateway 6.61ms 3.24k
linkered 7.62ms 2.82k
zuul 12.56ms 2.09k
none 2.09ms 11.77k

說明

  • 這裡的 Zuul 為 1.x 版本,是一個基於阻塞 IO 的 API Gateway
  • Zuul 已經發布了 Zuul 2.x,基於 Netty,非阻塞的,支援長連線,但 Spring Cloud 暫時還沒有整合計劃
  • Linkerd 基於 Scala 實現的、目前市面上僅有的生產級別的 Service Mesh(其他諸如 Istio、Conduit 暫時還不能用於生產)。

相關文章