当前位置: 首页 > news >正文

深圳卫健委最新通告优化大师电脑版下载

深圳卫健委最新通告,优化大师电脑版下载,做磁力搜索网站违法吗,如何做一份营销策划方案前提 本文获取请求、响应body大小方法的前提 : 网关只做转发逻辑,不修改请求、相应的body内容。 SpringCloud Gateway内部的机制类似下图,HttpServer(也就是NettyServer)接收外部的请求,在Gateway内部请求将会通过Htt…

前提

本文获取请求、响应body大小方法的前提 : 网关只做转发逻辑,不修改请求、相应的body内容。
SpringCloud Gateway内部的机制类似下图,HttpServer(也就是NettyServer)接收外部的请求,在Gateway内部请求将会通过HttpClient(Netty实现的客户端)发送给后端应用。
本文的body获取方式,基于HttpClient端实现,通过获取HttpClient发送、接收后端的请求、响应body实现。如果SpringCloudGateway内部逻辑修改了body,那么本文方式获取的body大小将会存在歧义误差。
如果想要在HttpServer层获取到报文大小,可以尝试自定义实现Netty的ChannelDuplexHandler,尝试获取到报文大小。
在这里插入图片描述

SpringCloud Gateway底层基于异步模型Netty实现,调用时相关的body内容不直接加载到内存。如果使用简单的SpringCloud Gateway Filter读取报文,读取body大小,会大幅影响网关性能。因此需要考虑一种方法,在不影响网关性能的前提下,获取请求、响应body大小。

方式一、重写SpringCloudGateway Filter类

重写 NettyRoutingFilter 获取 Request Body

重写Gateway自带的org.springframework.cloud.gateway.filter.NettyRoutingFilter
修改类的filter内的代码,在底层获取请求body的大小,并在exchange保存。

Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange).headers(headers -> {...}).request(method).uri(url).send((req, nettyOutbound) -> {...return nettyOutbound.send(request.getBody().map(body -> {// 修改此处代码,获取请求body的大小,并将获取到的结果存入exchange内。int size = body.readableByteCount();exchange.getAttributes().put("gw-request-body-size", size);return getByteBuf(body);}));}).responseConnection((res, connection) -> {...

重写 NettyWriteResponseFilter 获取 Response Body

重写Gateway自带的org.springframework.cloud.gateway.filter.NettyWriteResponseFilter
修改类filter内的代码,在底层获取响应body的大小,并在exchange保存。

return chain.filter(exchange).doOnError(throwable -> cleanup(exchange)).then(Mono.defer(() -> {...// TODO: needed?final Flux<DataBuffer> body = connection.inbound().receive().retain().map(byteBuf -> {// 获取响应报文的长度,并将结果写入exchange内。int respSize = byteBuf.readableBytes();exchange.getAttributes().put("gw-response-body-size", respSize);return wrap(byteBuf, response);});...

自定义Filter打印报文大小

通过上述的2个方法,request、response body的大小已经写入exchange内,只需要实现一个自定义的Filter,就可以获取到报文的大小。假设自定义的Filter命名为BodySizeFilter,它的Order需要在NettyWriteResponseFilter之前。
在这里插入图片描述

在filter方法内,从exchange获取request、response body大小。

@Slf4j
@Component
public class BodySizeFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return chain.filter(exchange).then(Mono.defer(() -> {Integer exchangeReq = exchange.getAttribute("gw-request-body-size");Integer exchangeResp = exchange.getAttribute("gw-response-body-size");log.info("req from exchange: {}", exchangeReq);log.info("resp from exchange: {}", exchangeResp);respSize.set(null);reqSize.set(null);return Mono.empty();}));}@Overridepublic int getOrder() {return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;}
}

方式二、自定义Netty Handler

另一种方式是基于Netty的Hander,非重写SpringCloud Gateway类。本文构建的SpringCloudGateway版本为2.2.9.RELEASE

实现自定义的Netty ChannelDuplexHandler

重写2个方法 write、channelRead。

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.UUID;@Slf4j
public class HttpClientLoggingHandler extends ChannelDuplexHandler {private static final AttributeKey<Long> RESP_SIZE = AttributeKey.valueOf("resp-size");private static final AttributeKey<Long> REQ_SIZE = AttributeKey.valueOf("req-size");@Overridepublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {if (msg instanceof ByteBuf) {final ByteBuf buf = (ByteBuf) msg;// 读取报文大小,一笔请求可能存在多个 msg,也就是一个请求报文,可能分多次经过write方法。int length = buf.readableBytes();long size;// 将结果以attribute形式保存在channel内,一笔完整的调用对应一个完整的context上下文。Attribute<Long> sizeAttr = ctx.channel().attr(REQ_SIZE);if (sizeAttr.get() == null) {size = 0L;} else {size = sizeAttr.get();}// 每次累加当前请求的报文大小。size += length;ctx.channel().attr(REQ_SIZE).set(size);}super.write(ctx, msg, promise);}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {if (msg instanceof ByteBuf) {final ByteBuf buf = (ByteBuf) msg;// 获取响应body的大小,一笔响应可能存在多个 msg,也就是一个响应报文,可能分多次经过channelRead方法。int length = buf.readableBytes();long size;Attribute<Long> sizeAttr = ctx.channel().attr(RESP_SIZE);if (sizeAttr.get() == null) {size = 0L;} else {size = ctx.channel().attr(RESP_SIZE).get();}size += length;// 将结果以attribute形式保存在channel内,一笔完整的调用对应一个完整的context上下文。ctx.channel().attr(RESP_SIZE).set(size);}super.channelRead(ctx, msg);}
}

将自定义Handler配置到网关内。

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.config.HttpClientCustomizer;
import org.springframework.context.annotation.Configuration;
import reactor.netty.channel.BootstrapHandlers;
import reactor.netty.http.client.HttpClient;@Slf4j
@Configuration
public class GwHttpClientCustomizer implements HttpClientCustomizer {@Overridepublic HttpClient customize(HttpClient client) {// 本文基于2.2.9.RELEASE的SpringCloud Gateway实现。return client.tcpConfiguration(tcpClient ->tcpClient.bootstrap(b ->BootstrapHandlers.updateConfiguration(b, "client-log", (connectionObserver, channel) -> {channel.pipeline().addFirst("client-log", new HttpClientLoggingHandler());})));}
}

通过上述自定义的方法,一笔完整的调用中请求、响应body的大小,已经被计算保存在netty channel内,只需要自定义SpringCloud Gateway Filter获取到结果。

import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.netty.Connection;import java.util.function.Consumer;import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CLIENT_RESPONSE_CONN_ATTR;/*** @author luobo on 2023/08/01 3:51 PM*/
@Slf4j
@Component
public class BodySizeFilter implements GlobalFilter, Ordered {private static final AttributeKey<Long> REQ_SIZE = AttributeKey.valueOf("req-size");private static final AttributeKey<Long> RESP_SIZE = AttributeKey.valueOf("resp-size");@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return chain.filter(exchange).then(Mono.defer(() -> {// SpringCloud Gateway内将每个调用的Connection保存在exchange内// connection 可以获取到 channelConnection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR);Attribute<Long> respSize = connection.channel().attr(RESP_SIZE);Attribute<Long> reqSize = connection.channel().attr(REQ_SIZE);long resp;if (respSize.get() == null) {resp = 0L;} else {resp = respSize.get();}long req;if (reqSize.get() == null) {req = 0L;} else {req = reqSize.get();}log.info("------------------------> resp size: {}", resp);log.info("------------------------> req size: {}", req);// 每次调用结束需要清空保存的值(因为连接会复用)respSize.set(null);reqSize.set(null);return Mono.empty();}));}@Overridepublic int getOrder() {return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;}
}

通过此方法获取的body大小会比真实的body大 ,因为它包含了请求和响应头的信息。


总结

本人更加推荐使用方式一。

http://www.hengruixuexiao.com/news/24894.html

相关文章:

  • 可以做婚礼视频的网站有哪些优化关键词的方法正确的是
  • 网站开发说明书交换友链要注意什么
  • 中海园林建设有限公司网站包括哪些内容
  • 小企业网站免费建设百度付费推广的费用
  • 万网怎么发布网站福州seo推广服务
  • 埃及网站后缀永久免费的培训学校管理软件
  • 使用vue做简单网站教程十种网络推广的方法
  • 免费做简单网站北京网站建设制作公司
  • 昌吉住房和城乡建设局网站seo关键词优化外包
  • 网络营销与网站推广的网络营销课程ppt
  • 先做网站还是做APP电子商务与网络营销题库
  • 网站二维码收费怎么做宁波seo怎么做引流推广
  • 做网站上传照片的尺寸怎么查百度收录
  • 贵阳做网站kuhugzseo是指什么岗位
  • 在域名做网站外链网站是什么
  • 驻马店做网站多少钱营销方案100个软文
  • 河北通信建设有限公司网站网络营销的概念及内容
  • ppt的网站导航栏怎么做的在线检测网站安全
  • 做网站运营还是翻译西地那非片的正确服用方法
  • 偃师建网站那家公司好搜索关键词排名提升
  • 网站维护主要是做哪些百度收录量查询
  • 河北综合网站建设系列百度识图查图片
  • 消防做ccc去那个网站奶茶网络营销策划方案
  • 网站建设中页面html直播代运营公司
  • 济南网站建设 选搜点o百度浏览器主页网址
  • wordpress购物网站爆款采集推广引流软件
  • 淮安那家公司做网站优秀企业网站模板
  • 网站下载速度测试宁波百度seo排名优化
  • 手机有软件做ppt下载网站有哪些内容吗推广普通话宣传内容
  • 兰州专业做网站怎么做百度网页