【第15章】Spring Cloud之Gateway网关过滤器(URL黑名单)


前言

上一章我们通过,路由断言根据请求IP地址的黑名单功能,作用范围比较大。

这一章,我们通过网关过滤器来实现特定请求url的黑名单功能,作用范围进一步细化到接口。


一、常用网关过滤器

官方内置的网关过滤器太多了,这里我只介绍常用的部分
网关过滤器又分为前置和后置,比较典型的有:AddRequestHeader(前),AddResponseHeader(后)

1. 常用过滤器

过滤器类型用法描述
AddRequestHeader- AddRequestHeader=X-Request-red, blue将X-Request-red:blue请求头添加到所有匹配请求的下游请求头中。
AddRequestHeadersIfNotPresent- AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green在请求头不存在的情况下,为所有匹配请求的下游请求标头添加了2个标头X-Request-Color-1:bule和X-Request-Color-2:green
AddRequestParameter- AddRequestParameter=red, blue将为所有匹配的请求在下游请求的查询参数中添加red=blue。
AddResponseHeader- AddResponseHeader=X-Response-Red, Blue这会将X-Response-Red:Blue添加到所有匹配请求的下游响应头中。
RemoveRequestHeader- RemoveRequestHeader=X-Request-Foo这将在X-Request-Foo请求头头被发送到下游之前将其删除。
RemoveRequestParameter- RemoveRequestParameter=red这将在向下游发送请求之前删除红色查询参数。
RemoveResponseHeader- RemoveResponseHeader=X-Response-Foo这将在响应返回给网关客户端之前从响应头中删除X-Response-Foo。
PrefixPath- PrefixPath=/mypath将为所有匹配请求添加前缀/mypath。因此,对/hello的请求被发送到/mypath/hello。
StripPrefix- StripPrefix=2当通过网关向/name/blue/red发出请求时,向nameservice发出的请求替换为nameservice/red。

2. 示例

RewritePath

对于/red/blue的请求路径,这会在发出下游请求之前将路径设置为/blue。请注意,由于YAML规范,$应该替换为$\

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://example.org
        predicates:
        - Path=/red/**
        filters:
        - RewritePath=/red/?(?<segment>.*), /$\{segment}

ModifyRequestBody

修改请求正文

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")
            .filters(f -> f.prefixPath("/httpbin")
                .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
                    (exchange, s) -> Mono.just(new Hello(s.toUpperCase())))).uri(uri))
        .build();
}

static class Hello {
    String message;

    public Hello() { }

    public Hello(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

ModifyResponseBody

修改响应正文

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
            .filters(f -> f.prefixPath("/httpbin")
                .modifyResponseBody(String.class, String.class,
                    (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri))
        .build();
}

3. Default Filters

要添加过滤器并将其应用于所有路由,可以使用spring.cloud.gateway.default-filters。此属性接受过滤器列表。以下列表定义了一组默认过滤器:

spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/httpbin

更多网关过滤器请查看

二、定义接口服务

上一章我们使用的是提供者服务,这里就使用消费者服务,配置看起来会更加直观。

1. 定义接口

定义三个服务,分别是:

  • user-service/hello
  • user-service/hello1
  • user-service/hello2
package org.example.nacos.consumer.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Create by zjg on 2024/7/21
 */
@RestController
@RequestMapping("/consumer/")
public class HelloController {
    @RequestMapping("hello")
    public String hello(){
        return "hello consumer";
    }
    @RequestMapping("hello1")
    public String hello1(){
        return "hello consumer";
    }
    @RequestMapping("hello2")
    public String hello2(){
        return "hello consumer";
    }
}

三、自定义过滤器

1. 过滤器类

package org.example.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.validation.constraints.NotEmpty;
import org.example.common.model.Result;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.route.Route;
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 org.springframework.validation.annotation.Validated;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
import static org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType.GATHER_LIST;

/**
 * Create by zjg on 2024/7/24
 */
@Component
public class BlackListGatewayFilterFactory extends AbstractGatewayFilterFactory<BlackListGatewayFilterFactory.Config> {
    public BlackListGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            String path = request.getURI().getPath();
            if (config.url.contains(path)) {
                response.setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                Result result = Result.error(HttpStatus.NOT_ACCEPTABLE.value(), "接口服务禁用", "该接口服务已加入黑名单,禁止访问!");
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    return response.writeWith(Flux.just(response.bufferFactory().wrap(objectMapper.writeValueAsBytes(result))));
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
            }
            return chain.filter(exchange);
        };
    }

    @Override
    public ShortcutType shortcutType() {
        return GATHER_LIST;
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("url");
    }

    @Validated
    public static class Config {
        @NotEmpty
        private List<String> url = new ArrayList<>();

        public List<String> getUrl() {
            return url;
        }

        public void setUrl(List<String> url) {
            this.url = url;
        }
    }
}

2. 应用配置

spring:
  cloud:
    gateway:
      routes:
      - id: provider-service
        uri: lb://provider-service
        predicates:
        - Path=/provider/**
        - BlackRemoteAddr=192.168.1.1/24,127.0.0.1,192.168.0.102
      - id: consumer-service
        uri: lb://consumer-service
        predicates:
        - Path=/consumer/**
        filters:
        - BlackList=/consumer/hello1,/consumer/hello2

四、单元测试

1. 正常

localhost:8888/consumer/hello在这里插入图片描述

2. 黑名单

localhost:8888/consumer/hello1
在这里插入图片描述

localhost:8888/consumer/hello2
在这里插入图片描述


总结

回到顶部

这样我们就可以通过配置文件轻松地控制接口的对外服务。

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值