Spring Cloud基于请求体的路由实现技术求助
基于请求体内容的API网关路由实现方案
以下是针对主流API网关的具体实现方案,覆盖Spring Cloud Gateway、Apache APISIX、Kong三种常用场景:
1. Spring Cloud Gateway 实现方式
Spring Cloud Gateway可通过内置的RequestBodyRoutePredicateFactory或自定义逻辑实现基于请求体的路由,需注意解决请求体只能读取一次的问题。
步骤1:配置路由规则
在application.yml中定义路由,通过请求体内容匹配目标服务:
spring: cloud: gateway: routes: - id: service-a-type1 uri: http://service-a/v1/type1 predicates: - Path=/serve-this-request - name: RequestBody args: pattern: '{"service":"service-a","type":"type1"}' matchType: CONTAINS - id: service-b-type5 uri: http://service-b/v1/type5 predicates: - Path=/serve-this-request - name: RequestBody args: pattern: '{"service":"service-b","type":"type5"}' matchType: CONTAINS - id: service-a-type2 uri: http://service-a/v1/type2 predicates: - Path=/serve-this-request - name: RequestBody args: pattern: '{"service":"service-a","type":"type2"}' matchType: CONTAINS - id: service-b-type2 uri: http://service-b/v1/type2 predicates: - Path=/serve-this-request - name: RequestBody args: pattern: '{"service":"service-b","type":"type2"}' matchType: CONTAINS - id: service-c-type3 uri: http://service-c/v1/type3 predicates: - Path=/serve-this-request - name: RequestBody args: pattern: '{"service":"service-c","type":"type3"}' matchType: CONTAINS
步骤2:添加请求体缓存过滤器
由于请求体默认只能读取一次,需自定义过滤器缓存请求体,确保后续路由断言能重复读取:
@Component public class BodyCacheFilter implements GatewayFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); if (request.getHeaders().getContentLength() > 0) { return DataBufferUtils.join(request.getBody()) .map(dataBuffer -> { byte[] bytes = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); return bytes; }) .flatMap(bytes -> { ServerHttpRequestDecorator decoratedRequest = new ServerHttpRequestDecorator(request) { @Override public Flux<DataBuffer> getBody() { return Flux.just(bufferFactory().wrap(bytes)); } }; return chain.filter(exchange.mutate().request(decoratedRequest).build()); }); } return chain.filter(exchange); } }
将该过滤器添加到所有路由的filters列表中即可。
2. Apache APISIX 实现方式
APISIX可通过Lua脚本直接解析请求体,动态设置上游服务地址和URI。
创建路由规则
通过Admin API配置路由,嵌入Lua脚本处理路由逻辑:
curl http://apisix-admin:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri": "/serve-this-request", "plugins": { "request-validation": { "body_schema": { "type": "object", "properties": { "service": {"type": "string"}, "type": {"type": "string"} } } } }, "script": "local body = core.request.get_body() local json_body = core.json.decode(body) if json_body.service == \"service-a\" and json_body.type == \"type1\" then core.var.upstream_host = \"service-a\" core.var.upstream_uri = \"/v1/type1\" elseif json_body.service == \"service-b\" and json_body.type == \"type5\" then core.var.upstream_host = \"service-b\" core.var.upstream_uri = \"/v1/type5\" elseif json_body.service == \"service-a\" and json_body.type == \"type2\" then core.var.upstream_host = \"service-a\" core.var.upstream_uri = \"/v1/type2\" elseif json_body.service == \"service-b\" and json_body.type == \"type2\" then core.var.upstream_host = \"service-b\" core.var.upstream_uri = \"/v1/type2\" elseif json_body.service == \"service-c\" and json_body.type == \"type3\" then core.var.upstream_host = \"service-c\" core.var.upstream_uri = \"/v1/type3\" end" }'
3. Kong 实现方式
Kong通过自定义Lua插件实现请求体解析与路由转发逻辑。
自定义插件核心代码
local plugin = { PRIORITY = 1000, VERSION = "0.1", } function plugin:access(conf) local body = kong.request.get_body() if body.service == "service-a" and body.type == "type1" then kong.service.set_target("service-a", 80) kong.service.set_path("/v1/type1") elseif body.service == "service-b" and body.type == "type5" then kong.service.set_target("service-b", 80) kong.service.set_path("/v1/type5") elseif body.service == "service-a" and body.type == "type2" then kong.service.set_target("service-a", 80) kong.service.set_path("/v1/type2") elseif body.service == "service-b" and body.type == "type2" then kong.service.set_target("service-b", 80) kong.service.set_path("/v1/type2") elseif body.service == "service-c" and body.type == "type3" then kong.service.set_target("service-c", 80) kong.service.set_path("/v1/type3") end end return plugin
将插件打包部署到Kong后,为/serve-this-request路由启用该插件即可。
内容的提问来源于stack exchange,提问作者spyder
相关产品推荐
相关产品推荐

