保健励志美文体育育儿作文
投稿投诉
作文动态
热点娱乐
育儿情感
教程科技
体育养生
教案探索
美文旅游
财经日志
励志范文
论文时尚
保健游戏
护肤业界

springbootgateway记录请求和响应日志

  springbootgateway记录请求和响应日志
  springcloudgateway是基于webflux的项目,因而不能跟使用springmvc一样直接获取requestbody,因此需要重新构造再转发。
  如果我们在springcloudgateway封装之前读取了一次requestbody,比如打印requestbody日志,在下游获取数据的时候会出现错误:〔springcloud〕〔error〕java。lang。IllegalStateException:Onlyoneconnectionreceivesubscriberallowed。因为requestbody只能读取一次,它是属于消费类型的。
  出现这样的原因是InputStream的read()方法内部有一个postion,标志当前流被读取到的位置,每读取一次,该标志就会移动一次,如果读到最后,read()会返回1,表示已经读取完了。如果想要重新读取则需要调用reset()方法,position就会移动到上次调用mark的位置,mark默认是0,所以就能从头再读了。调用reset()方法的前提是已经重写了reset()方法,当然能否reset也是有条件的,它取决于markSupported()方法是否返回true,InputStream默认不实现reset(),并且markSupported()默认也是返回false。综上,InputStream默认不实现reset的相关方法,而ServletInputStream也没有重写reset的相关方法,这样就无法重复读取流,这就是我们从request对象中获取的输入流就只能读取一次的原因。
  直接上代码importlombok。Data;importjava。io。Serializable;importjava。util。Date;DatapublicclassGatewayLogimplementsSerializable{privatestaticfinallongserialVersionUID1983879536575766072L;访问实例privateStringtargetServer;请求路径privateStringrequestPath;请求方法privateStringrequestMethod;协议privateStringschema;请求体privateStringrequestBody;响应体privateStringresponseData;请求ipprivateStringip;请求时间privateDaterequestTime;响应时间privateDateresponseTime;执行时间privatelongexecuteTime;返回码privatelongcode;返回数据类型privateStringresponseContentType;请求数据类型privateStringrequestContentType;请求用户idprivateStringuserId;}
  publicinterfaceAccessLogService{voidsaveAccessLog(GatewayLoggatewayLog);}
  importcn。hutool。core。collection。CollectionUtil;importcom。shouwei。gateway。entity。GatewayLog;importcom。shouwei。gateway。service。AccessLogService;importcom。shouwei。gateway。utils。IpUtils;importlombok。extern。slf4j。Slf4j;importorg。apache。commons。lang。StringUtils;importorg。reactivestreams。Publisher;importorg。springframework。beans。factory。annotation。Autowired;importorg。springframework。cloud。gateway。filter。GatewayFilterChain;importorg。springframework。cloud。gateway。filter。GlobalFilter;importorg。springframework。cloud。gateway。filter。factory。rewrite。CachedBodyOutputMessage;importorg。springframework。cloud。gateway。route。Route;importorg。springframework。cloud。gateway。support。BodyInserterContext;importorg。springframework。cloud。gateway。support。ServerWebExchangeUtils;importorg。springframework。core。Ordered;importorg。springframework。core。ResolvableType;importorg。springframework。core。io。buffer。;importorg。springframework。http。HttpHeaders;importorg。springframework。http。MediaType;importorg。springframework。http。codec。HttpMessageReader;importorg。springframework。http。codec。multipart。FormFieldPart;importorg。springframework。http。codec。multipart。Part;importorg。springframework。http。server。reactive。ServerHttpRequest;importorg。springframework。http。server。reactive。ServerHttpRequestDecorator;importorg。springframework。http。server。reactive。ServerHttpResponse;importorg。springframework。http。server。reactive。ServerHttpResponseDecorator;importorg。springframework。stereotype。Component;importorg。springframework。util。LinkedMultiValueMap;importorg。springframework。util。MultiValueMap;importorg。springframework。web。reactive。function。BodyInserter;importorg。springframework。web。reactive。function。BodyInserters;importorg。springframework。web。reactive。function。server。HandlerStrategies;importorg。springframework。web。reactive。function。server。ServerRequest;importorg。springframework。web。server。ServerWebExchange;importorg。springframework。web。util。UriComponentsBuilder;importreactor。core。publisher。Flux;importreactor。core。publisher。Mono;importjava。io。UnsupportedEncodingException;importjava。nio。charset。StandardCharsets;importjava。util。;importjava。util。regex。Matcher;importjava。util。regex。Pattern;全局拦截器,作用所有的微服务1。对请求的API调用过滤,记录接口的请求时间,方便日志审计、告警、分析等运维操作2。后期可以扩展对接其他日志系统Slf4jComponentpublicclassAccessLogFilterimplementsGlobalFilter,Ordered{defaultHttpMessageReader。privatestaticfinalListHttpMessageReaderlt;?MESSAGEREADERSHandlerStrategies。withDefaults()。messageReaders();AutowiredprivateAccessLogServiceaccessLogService;privatefinalListHttpMessageReaderlt;?messageReadersHandlerStrategies。withDefaults()。messageReaders();顺序必须是1,否则标准的NettyWriteResponseFilter将在您的过滤器得到一个被调用的机会之前发送响应也就是说如果不小于1,将不会执行获取后端响应的逻辑returnOverridepublicintgetOrder(){return100;}OverrideSuppressWarnings(unchecked)publicMonoVoidfilter(ServerWebExchangeexchange,GatewayFilterChainchain){ServerHttpRequestrequestexchange。getRequest();请求路径StringrequestPathrequest。getPath()。pathWithinApplication()。value();RouteroutegetGatewayRoute(exchange);StringipAddressIpUtils。getIpAddress(request);GatewayLoggatewayLognewGatewayLog();gatewayLog。setSchema(request。getURI()。getScheme());gatewayLog。setRequestMethod(request。getMethodValue());gatewayLog。setRequestPath(requestPath);gatewayLog。setTargetServer(route。getId());gatewayLog。setRequestTime(newDate());gatewayLog。setIp(ipAddress);MediaTypemediaTyperequest。getHeaders()。getContentType();gatewayLog。setRequestContentType(mediaType。getType()mediaType。getSubtype());json格式if(MediaType。APPLICATIONJSON。isCompatibleWith(mediaType)){returnwriteBodyLog(exchange,chain,gatewayLog);}formdata格式elseif(MediaType。MULTIPARTFORMDATA。isCompatibleWith(mediaType)MediaType。APPLICATIONFORMURLENCODED。isCompatibleWith(mediaType)){returnreadFormData(exchange,chain,gatewayLog);}其他格式else{returnwriteBasicLog(exchange,chain,gatewayLog);}}privateMonoVoidwriteBasicLog(ServerWebExchangeexchange,GatewayFilterChainchain,GatewayLogaccessLog){returnDataBufferUtils。join(exchange。getRequest()。getBody())。flatMap(dataBuffer{DataBufferUtils。retain(dataBuffer);finalFluxDataBuffercachedFluxFlux。defer(()Flux。just(dataBuffer。slice(0,dataBuffer。readableByteCount())));finalServerHttpRequestmutatedRequestnewServerHttpRequestDecorator(exchange。getRequest()){OverridepublicFluxDataBuffergetBody(){returncachedFlux;}OverridepublicMultiValueMapString,StringgetQueryParams(){returnUriComponentsBuilder。fromUri(exchange。getRequest()。getURI())。build()。getQueryParams();}};StringBuilderbuildernewStringBuilder();MultiValueMapString,StringqueryParamsexchange。getRequest()。getQueryParams();if(CollectionUtil。isNotEmpty(queryParams)){for(Map。EntryString,ListStringentry:queryParams。entrySet()){builder。append(entry。getKey())。append()。append(StringUtils。join(entry。getValue(),,));}}accessLog。setRequestBody(builder。toString());获取响应体ServerHttpResponseDecoratordecoratedResponserecordResponseLog(exchange,accessLog);returnchain。filter(exchange。mutate()。request(mutatedRequest)。response(decoratedResponse)。build())。then(Mono。fromRunnable((){打印日志writeAccessLog(accessLog);}));});}读取formdata数据paramexchangeparamchainparamaccessLogreturnprivateMonoVoidreadFormData(ServerWebExchangeexchange,GatewayFilterChainchain,GatewayLogaccessLog){returnDataBufferUtils。join(exchange。getRequest()。getBody())。flatMap(dataBuffer{DataBufferUtils。retain(dataBuffer);finalFluxDataBuffercachedFluxFlux。defer(()Flux。just(dataBuffer。slice(0,dataBuffer。readableByteCount())));finalServerHttpRequestmutatedRequestnewServerHttpRequestDecorator(exchange。getRequest()){OverridepublicFluxDataBuffergetBody(){returncachedFlux;}OverridepublicMultiValueMapString,StringgetQueryParams(){returnUriComponentsBuilder。fromUri(exchange。getRequest()。getURI())。build()。getQueryParams();}};finalHttpHeadersheadersexchange。getRequest()。getHeaders();if(headers。getContentLength()0){returnchain。filter(exchange);}ResolvableTyperesolvableType;if(MediaType。MULTIPARTFORMDATA。isCompatibleWith(headers。getContentType())){resolvableTypeResolvableType。forClassWithGenerics(MultiValueMap。class,String。class,Part。class);}else{解析applicationxwwwformurlencodedresolvableTypeResolvableType。forClass(String。class);}returnMESSAGEREADERS。stream()。filter(readerreader。canRead(resolvableType,mutatedRequest。getHeaders()。getContentType()))。findFirst()。orElseThrow(()newIllegalStateException(nosuitableHttpMessageReader。))。readMono(resolvableType,mutatedRequest,Collections。emptyMap())。flatMap(resolvedBody{if(resolvedBodyinstanceofMultiValueMap){LinkedMultiValueMapmap(LinkedMultiValueMap)resolvedBody;if(CollectionUtil。isNotEmpty(map)){StringBuilderbuildernewStringBuilder();finalPartbodyPartInfo(Part)((MultiValueMap)resolvedBody)。getFirst(body);if(bodyPartInfoinstanceofFormFieldPart){Stringbody((FormFieldPart)bodyPartInfo)。value();log。info(bodybody);builder。append(body)。append(body);}finalPartuidPartInfo(Part)((MultiValueMap)resolvedBody)。getFirst(uid);if(uidPartInfoinstanceofFormFieldPart){Stringuid((FormFieldPart)uidPartInfo)。value();log。info(uiduid);accessLog。setUserId(uid);if(builder。length()0){builder。append(uid)。append(uid);}else{builder。append(uid)。append(uid);}}finalParttimeStampPartInfo(Part)((MultiValueMap)resolvedBody)。getFirst(timeStamp);if(timeStampPartInfoinstanceofFormFieldPart){StringtimeStamp((FormFieldPart)timeStampPartInfo)。value();log。info(timeStamptimeStamp);if(builder。length()0){builder。append(timeStamp)。append(timeStamp);}else{builder。append(timeStamp)。append(timeStamp);}}finalParttokenPartInfo(Part)((MultiValueMap)resolvedBody)。getFirst(token);if(tokenPartInfoinstanceofFormFieldPart){Stringtoken((FormFieldPart)tokenPartInfo)。value();log。info(tokentoken);if(builder。length()0){builder。append(token)。append(token);}else{builder。append(token)。append(token);}}finalPartsignPartInfo(Part)((MultiValueMap)resolvedBody)。getFirst(sign);if(signPartInfoinstanceofFormFieldPart){Stringsign((FormFieldPart)signPartInfo)。value();log。info(signsign);if(builder。length()0){builder。append(sign)。append(sign);}else{builder。append(sign)。append(sign);}}accessLog。setRequestBody(builder。toString());}}else{accessLog。setRequestBody((String)resolvedBody);}获取响应体ServerHttpResponseDecoratordecoratedResponserecordResponseLog(exchange,accessLog);returnchain。filter(exchange。mutate()。request(mutatedRequest)。response(decoratedResponse)。build())。then(Mono。fromRunnable((){打印日志writeAccessLog(accessLog);}));});});}解决requestbody只能读取一次问题,参考:org。springframework。cloud。gateway。filter。factory。rewrite。ModifyRequestBodyGatewayFilterFactoryparamexchangeparamchainparamgatewayLogreturnSuppressWarnings(unchecked)privateMonowriteBodyLog(ServerWebExchangeexchange,GatewayFilterChainchain,GatewayLoggatewayLog){ServerRequestserverRequestServerRequest。create(exchange,messageReaders);MonoStringmodifiedBodyserverRequest。bodyToMono(String。class)。flatMap(body{gatewayLog。setRequestBody(body);returnMono。just(body);});通过BodyInserter插入body(支持修改body),避免requestbody只能获取一次BodyInserterbodyInserterBodyInserters。fromPublisher(modifiedBody,String。class);HttpHeadersheadersnewHttpHeaders();headers。putAll(exchange。getRequest()。getHeaders());thenewcontenttypewillbecomputedbybodyInserterandthensetintherequestdecoratorheaders。remove(HttpHeaders。CONTENTLENGTH);CachedBodyOutputMessageoutputMessagenewCachedBodyOutputMessage(exchange,headers);returnbodyInserter。insert(outputMessage,newBodyInserterContext())。then(Mono。defer((){重新封装请求ServerHttpRequestdecoratedRequestrequestDecorate(exchange,headers,outputMessage);记录响应日志ServerHttpResponseDecoratordecoratedResponserecordResponseLog(exchange,gatewayLog);记录普通的returnchain。filter(exchange。mutate()。request(decoratedRequest)。response(decoratedResponse)。build())。then(Mono。fromRunnable((){打印日志writeAccessLog(gatewayLog);}));}));}打印日志paramgatewayLog网关日志authorjavadailydate202132414:53privatevoidwriteAccessLog(GatewayLoggatewayLog){accessLogService。saveAccessLog(gatewayLog);}privateRoutegetGatewayRoute(ServerWebExchangeexchange){returnexchange。getAttribute(ServerWebExchangeUtils。GATEWAYROUTEATTR);}请求装饰器,重新计算headersparamexchangeparamheadersparamoutputMessagereturnprivateServerHttpRequestDecoratorrequestDecorate(ServerWebExchangeexchange,HttpHeadersheaders,CachedBodyOutputMessageoutputMessage){returnnewServerHttpRequestDecorator(exchange。getRequest()){OverridepublicHttpHeadersgetHeaders(){longcontentLengthheaders。getContentLength();HttpHeadershttpHeadersnewHttpHeaders();httpHeaders。putAll(super。getHeaders());if(contentLength0){httpHeaders。setContentLength(contentLength);}else{TODO:thiscausesaHTTP1。1411LengthRequiredonhttpbin。orghttpHeaders。set(HttpHeaders。TRANSFERENCODING,chunked);}returnhttpHeaders;}OverridepublicFluxDataBuffergetBody(){returnoutputMessage。getBody();}};}记录响应日志通过DataBufferFactory解决响应体分段传输问题。privateServerHttpResponseDecoratorrecordResponseLog(ServerWebExchangeexchange,GatewayLoggatewayLog){ServerHttpResponseresponseexchange。getResponse();DataBufferFactorybufferFactoryresponse。bufferFactory();returnnewServerHttpResponseDecorator(response){OverridepublicMonoVoidwriteWith(Publisherlt;?extendsDataBufferbody){if(bodyinstanceofFlux){DateresponseTimenewDate();gatewayLog。setResponseTime(responseTime);计算执行时间longexecuteTime(responseTime。getTime()gatewayLog。getRequestTime()。getTime());gatewayLog。setExecuteTime(executeTime);获取响应类型,如果是json就打印StringoriginalResponseContentTypeexchange。getAttribute(ServerWebExchangeUtils。ORIGINALRESPONSECONTENTTYPEATTR);log。info(originalResponseContentTypeoriginalResponseContentType);gatewayLog。setResponseContentType(originalResponseContentType);gatewayLog。setCode(this。getStatusCode()。value());if(ObjectUtils。equals(this。getStatusCode(),HttpStatus。OK)!StringUtil。isNullOrEmpty(originalResponseContentType)originalResponseContentType。contains(applicationjson)){Fluxlt;?extendsDataBufferfluxBodyFlux。from(body);returnsuper。writeWith(fluxBody。buffer()。map(dataBuffers{合并多个流集合,解决返回体分段传输DataBufferFactorydataBufferFactorynewDefaultDataBufferFactory();DataBufferjoindataBufferFactory。join(dataBuffers);byte〔〕contentnewbyte〔join。readableByteCount()〕;join。read(content);释放掉内存DataBufferUtils。release(join);StringresponseResultnewString(content,StandardCharsets。UTF8);log。info(responseResultresponseResult);gatewayLog。setResponseData(responseResult);returnbufferFactory。wrap(content);}));}}ifbodyisnotaflux。nevergotthere。returnsuper。writeWith(body);}};}}
  用到的依赖dependencygroupIdorg。springframework。cloudgroupIdspringcloudstartergatewayartifactIdversion2。2。5。RELEASEversiondependencydependencygroupIdorg。projectlombokgroupIdlombokartifactIdversion1。18。22versiondependency!huTool工具箱大全dependencygroupIdcn。hutoolgroupIdhutoolallartifactIdversion5。2。5versiondependency

我脑中的橡皮檫观后感人生短短几十载,时间像流水一般,生命是一个过程,可悲的是它不能重来!yuwenmi小编整理了我脑中的橡皮檫观后感,快来看看吧。我脑中的橡皮檫观后感一:我喜欢这个男人的霸道……2017年欢度春节作文导语:春节是中国人民的传统节日,出门在外的人们回到家里和亲人们欢聚一堂,晚上在一起看看电视、讲讲在外面的经历,腊月二十六也是新年前的最后一集市了,人们结伴去集市上买鞭炮、新衣服……有关爱国的作文2000字有关爱国的作文2000字各位尊敬的领导,同事:大家好!今天我的演讲题目是《试谈与时俱进的雷锋精神》:胡锦涛总书在参加全国政协十届四次会议民盟、民进界委员联组讨……初三议论文贫穷与富裕自古以来,百分之九十九,都希望自己可以富裕。我想,或许没有一个人迫切地盼望自己可以做一个贫穷的人。可是,有没有人会去理解贫穷、富裕?人们就算去理解了,终究只有一个答案:贫穷没有……为你,千万次等待作文人流中,我寻觅你的身影。我曾以为你会来,可是你没有。我从未想过今年的夏日会这般炎热,以至于睡梦中的我被一次次惊醒。末了,起身,下楼。今夜的月极圆,嵌在天空中,散着着……谁叫我是小孩唉!真倒霉,电视不许看,电脑不许玩,这也不可以,那也不可以,你说我活的累不累,电视要么不看,要么就只能看什么空中课堂,教你写字,电脑要么不玩,要玩就是写作文,写诗歌。大家想想,……我爱学习(小学版)妈妈说我以前不爱学习只爱玩儿!但是现在我爱学习了!是什么让我爱上学习的呢?那就接着往下看吧!首先我有几个非常有趣的老师,她们的课既生动、有趣,又非常好玩。先来说说我的班主……秋天的田园风光小学作文3篇秋天的田园风光作文篇1:在一阵阵凉爽的风中,秋天已经来了。田野里,一望无边的金色,像铺了一层金子似的,沉甸甸的果实压得稻秆直不起腰来,一阵风拂过,稻子随风舞蹈,像跳起了探……梦幻天使(1)我是一个的漂亮女学生,叫湘梦。在长满长春滕的名牌学校哈佛读大一,因为如花般的面容使我成为了公认的校花。一般人们都说头发长,见识短。但我学习成绩也不赖嘛!总是名列前茅,位居第一。……给手拉手小朋友的一封信你好!我是来自崇文实验学校五年级8班的郭孟华。我经过了老师的推荐知道了你们学校,并且希望与你能成为知己知彼的好朋友。虽然,我现在并不认识你,但是我是个爱交朋友的人,涉交能……严厉的妈妈作文5篇篇一:严厉的妈妈有一次我考试考得不好,只考了八十九分,回到家,妈妈看我的试卷,一看这么差,就很生气眼睛变成了红色,房子都好像要塌下来似的。我很害怕,就像老虎追兔子,……吾乃何许人也?冯建是也!吾本天上星宿,因犯弥错,故而遭玉帝贬谪下降于凡间与尔等同窗共事,是尔等之福也,幸也!自吾降地之日起,吾便忘其前世,习性与众人无异也!时光流转,须臾……
我学会了种菜作文6篇我们生活在钢筋水泥丛林中的城里人没有大片的土地,怎么种菜呢?种植夏日盛开的向日葵、秋日的银叶菊、冬日的彩叶芋、春日的仙客来与郁金香。当然,最方便的是种蔬菜,在阳台上种植小白菜、……发掘美丽初中作文700字著名雕塑家罗丹说:生活中不是缺少美,而是缺少发现美的眼睛。然而金无足赤,人无完人的古训并没有让我们在认识事物时发生实质性的变化《安徒生童话》中有一个小故事:一只鹳鸟偶然在一群鸡……五年级保护环境原理雾霾的作文【作文1:保护环境,远离雾霾】以前,我们一旦抬头,看到的是蓝天白云,是阳光明媚。而现在,我们抬头,只能看到一片灰蒙蒙的雾,远方的楼早就陷入雾里,看不见了,周围笼罩在雾里,……安永慢病管理和健康管理或成互联网医疗行业快速发展新引擎澎湃财讯互联网医疗平台的短期发展前景向好。其中,慢病管理和健康管理,或将成为国内互联网医疗下一步发展的重要引擎。5月16日,安永大中华区生命科学与医疗健康行业联席主管合伙……郭明錤AirPods等苹果配件未来将全面采用USBC接口上周早些时候,天风国际知名苹果分析师郭明錤宣称苹果(AAPL。US)计划至少在2023年发布的一款iPhone15机型中增加USBC接口。他在后续的推文中声称,AirPods、……作文精选集父爱【篇一:父爱如山】天空乌云密布,难道是要下雨了?果然不出我所料,放学是一场倾盆大雨从天而降。校园的门口,被家长挤得水泄不通,有的家长拿着雨衣,有的带着雨伞,不一会儿……2022长虹空调开启全民行动洁净空间活动,助力健康一夏夏天即将到来,还有什么比西瓜空调WiFi三件套更让人幸福的事?边吹空调边吃西瓜边追剧,你吃下的可不仅仅是西瓜了,还有灰尘、细菌。这一切就来自于家里久未清洗的空调,也许你会说,我……巴黎圣母院读后感《巴黎圣母院》是法国19世纪着名作家雨果的代表作。小说描写了15世纪光怪陆离的巴黎生活,作者用对比的手法刻画了一群性格鲜明生动、极富艺术感染力的人物形象,以之间错综复杂的矛盾纠……关于描写理想是一盏灯的议论文江水因为有了理想,并能在信念中勇往直前,才得以冲破群山阻挡,开创了九曲回肠的壮美;寒梅因为有了理想,并能在理想中坚持不懈,才得以战胜狂风暴雪,绽放了凌寒独立的风姿;苍鹰因为有了……果汁闯祸了作文范文暑假里的一天,妈妈有事出去了,我和爸爸待在家里。我在楼上悠哉悠哉地看着电视,还喝起了果汁。而爸爸却在楼下的电脑上打牌。我一边看电视,一边伸出手去拿果汁的被子,呯,只见那被……垒高自己作文没有人一开始就站在高处,需要自己垒高自己,达到人生巅峰,在这过程,注定是艰辛而又困苦的,而能克服这过程并踏上高峰的也必是个不平凡之人,诸如此类的人,在历史长河中,比比皆是。……写给2049年后自己一封信作文太阳落在了我的头顶,叫醒了死气沉沉的家。机械式的声音传来:公主,早安。今天天气晴朗。最近大家在讨论20XX年的时空,一起加入吧!我懒懒得点了个头,心想20XX年是怎样的呢。嗯啊……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网