Kotlin 如何在SpringCloudGateway中编写用于检查请求正文的自定义GlobalFilter?
我想验证Kotlin 如何在SpringCloudGateway中编写用于检查请求正文的自定义GlobalFilter?,kotlin,spring-cloud,spring-cloud-gateway,Kotlin,Spring Cloud,Spring Cloud Gateway,我想验证GlobalFilter中的正文 我需要读取包含正文校验和的两个http头,并将其与正文本身进行比较: internal class MyFilter : GlobalFilter { override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain) = ByteArrayDecoder() .decodeToMono(
GlobalFilter
中的正文
我需要读取包含正文校验和的两个http头,并将其与正文本身进行比较:
internal class MyFilter : GlobalFilter {
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain) =
ByteArrayDecoder()
.decodeToMono(
exchange.request.body,
ResolvableType.forClass(ByteBuffer::class.java),
exchange.request.headers.contentType,
null
)
.flatMap { /* my logic checking body against request headers */ chain.filter(exchange) }
}
问题是decodingtomino
阻塞并且不转发请求
如何正确解码正文?我已成功编写了一个在读取正文后不会卡住的过滤器:
interface BodyFilter {
fun filter(
body: Mono<ByteArrayResource>,
exchange: ServerWebExchange,
passRequestFunction: () -> Mono<Void>
): Mono<Void>
}
class HeaderAndBodyGlobalFilter(private val bodyFilter: BodyFilter) : GlobalFilter {
private val messageReaders: List<HttpMessageReader<*>> = HandlerStrategies.withDefaults().messageReaders()
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
val serverRequest: ServerRequest = ServerRequest.create(exchange, messageReaders)
val body: Mono<ByteArrayResource> = serverRequest.bodyToMono<ByteArrayResource>(ByteArrayResource::class.java)
return bodyFilter.filter(body, exchange) { reconstructRequest(body, exchange, chain) }
}
private fun reconstructRequest(
body: Mono<ByteArrayResource>,
exchange: ServerWebExchange,
chain: GatewayFilterChain
): Mono<Void> {
val headers: HttpHeaders = writableHttpHeaders(exchange.request.headers)
val outputMessage = CachedBodyOutputMessage(exchange, headers)
return BodyInserters.fromPublisher(
body,
ByteArrayResource::class.java
).insert(outputMessage, BodyInserterContext())
.then(Mono.defer {
val decorator: ServerHttpRequestDecorator = decorate(
exchange, headers, outputMessage
)
chain
.filter(exchange.mutate().request(decorator).build())
})
}
private fun decorate(
exchange: ServerWebExchange,
headers: HttpHeaders,
outputMessage: CachedBodyOutputMessage
): ServerHttpRequestDecorator {
return object : ServerHttpRequestDecorator(exchange.request) {
override fun getHeaders(): HttpHeaders {
val contentLength = headers.contentLength
val httpHeaders = HttpHeaders()
httpHeaders.putAll(super.getHeaders())
if (contentLength > 0) {
httpHeaders.contentLength = contentLength
} else {
// TODO: this causes a 'HTTP/1.1 411 Length Required' // on
// httpbin.org
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked")
}
return httpHeaders
}
override fun getBody(): Flux<DataBuffer> {
return outputMessage.body
}
}
}
}
接口体过滤器{
趣味过滤器(
正文:Mono,
exchange:ServerWebExchange,
passRequestFunction:()->Mono
):Mono
}
类HeaderAndBodyGlobalFilter(私有值bodyFilter:bodyFilter):全局过滤器{
private val messageReaders:List=HandlerStrategies.withDefaults().messageReaders()
覆盖有趣的过滤器(exchange:ServerWebExchange,链:GatewayFilterChain):Mono{
val serverRequest:serverRequest=serverRequest.create(exchange、messageReaders)
val body:Mono=serverRequest.bodyToMono(ByteArrayResource::class.java)
返回bodyFilter.filter(body,exchange){重构请求(body,exchange,chain)}
}
私人娱乐重建请求(
正文:Mono,
exchange:ServerWebExchange,
链:网关过滤器链
):Mono{
val headers:HttpHeaders=writableHttpHeaders(exchange.request.headers)
val outputMessage=CachedBodyOutputMessage(交换,标题)
返回BodyInserters.fromPublisher(
身体,
ByteArrayResource::class.java
).insert(outputMessage,BodyInserterContext())
.然后(单声道){
val decorator:ServerHttpRequestDecorator=decoration(
交换、标题、输出消息
)
链条
.filter(exchange.mutate().request(decorator.build())
})
}
私人娱乐装饰(
exchange:ServerWebExchange,
标题:HttpHeaders,
outputMessage:CachedBodyOutputMessage
):ServerHttpRequestDecorator{
返回对象:ServerHttpRequestDecorator(exchange.request){
重写fun getHeaders():HttpHeaders{
val contentLength=headers.contentLength
val httpHeaders=httpHeaders()
httpHeaders.putAll(super.getHeaders())
如果(contentLength>0){
httpHeaders.contentLength=contentLength
}否则{
//TODO:这会导致在上出现“HTTP/1.1 411所需长度”//
//httpbin.org
httpHeaders.set(httpHeaders.TRANSFER_编码,“分块”)
}
返回HttpHeader
}
重写fun getBody():Flux{
返回outputMessage.body
}
}
}
}
然后实现
BodyFilter
在失败时返回Mono.empty()
,或者在成功时调用passRequestFunction
。在过滤器中使用ModifyRequestBody过滤器?@Spencergib我还需要使用来自标题的信息(标题存储正文的校验和)-这就是为什么我认为GlobalFilter
非常适合。无论如何,我将更新问题以反映该信息。从该筛选器复制then@spencergibb非常感谢,执行:)