文章目录
前言
上一章我们通过,路由断言根据请求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. 正常
2. 黑名单
localhost:8888/consumer/hello1
localhost:8888/consumer/hello2
总结
这样我们就可以通过配置文件轻松地控制接口的对外服务。