完美解决spring cloud gateway 获取body内容并修改
发布日期:2021-09-18 00:51:48 浏览次数:13 分类:技术文章

本文共 5749 字,大约阅读时间需要 19 分钟。

完美解决spring cloud gateway 获取body内容并修改

 

之前写过一篇文章,如何获取body的内容。

Spring Cloud Gateway获取body内容,不影响GET请求
确实能够获取所有body的内容了,不过今天终端同学调试接口的时候和我说,遇到了400的问题,报错是这样的HTTP method names must be tokens,搜了一下,都是说https引起的。可我的项目还没用https,排除了。
想到是不是因为修改了body内容导致的问题,试着不修改body的内容,直接传给微服务,果然没有报错了。
问题找到,那就好办了,肯定是我新构建的REQUEST对象缺胳膊少腿了,搜索一通之后发现一篇大牛写的文章:
Spring Cloud Gateway(读取、修改 Request Body)
这里要再次表扬一下古哥,同样是中文文章,度娘却搜不到
不过文章中的spring cloud版本是
Spring Cloud: Greenwich.RC2
我本地是最新的Release版本RS3,并不能完全照搬过来,不过算是给了很大的启发(如何获取body以及重构)
下面给出我的代码
网关中对body内容进行解密然后验签

/** * @author tengdj * @date 2019/8/13 11:08 * 设备接口验签,解密 **/@Slf4jpublic class TerminalSignFilter implements GatewayFilter, Ordered {    private static final String AES_SECURTY = "XXX";    private static final String MD5_SALT = "XXX";    @Override    public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) { exchange.getAttributes().put("startTime", System.currentTimeMillis()); if (exchange.getRequest().getMethod().equals(HttpMethod.POST)) { //重新构造request,参考ModifyRequestBodyGatewayFilterFactory ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()); MediaType mediaType = exchange.getRequest().getHeaders().getContentType(); //重点 Mono
modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> { //因为约定了终端传参的格式,所以只考虑json的情况,如果是表单传参,请自行发挥 if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) || MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType)) { JSONObject jsonObject = JSONUtil.toJO(body); String paramStr = jsonObject.getString("param"); String newBody; try{ newBody = verifySignature(paramStr); }catch (Exception e){ return processError(e.getMessage()); } return Mono.just(newBody); } return Mono.empty(); }); BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class); HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getRequest().getHeaders()); //猜测这个就是之前报400错误的元凶,之前修改了body但是没有重新写content length headers.remove("Content-Length"); //MyCachedBodyOutputMessage 这个类完全就是CachedBodyOutputMessage,只不过CachedBodyOutputMessage不是公共的 MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers); return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> { ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage); return returnMono(chain, exchange.mutate().request(decorator).build()); })); } else { //GET 验签 MultiValueMap
map = exchange.getRequest().getQueryParams(); if (!CollectionUtils.isEmpty(map)) { String paramStr = map.getFirst("param"); try{ verifySignature(paramStr); }catch (Exception e){ return processError(e.getMessage()); } } return returnMono(chain, exchange); } } @Override public int getOrder() { return 1; } private Mono
returnMono(GatewayFilterChain chain,ServerWebExchange exchange){ return chain.filter(exchange).then(Mono.fromRunnable(()->{ Long startTime = exchange.getAttribute("startTime"); if (startTime != null){ long executeTime = (System.currentTimeMillis() - startTime); log.info("耗时:{}ms" , executeTime); log.info("状态码:{}" , Objects.requireNonNull(exchange.getResponse().getStatusCode()).value()); } })); } private String verifySignature(String paramStr) throws Exception{ log.info("密文{}", paramStr); String dParamStr; try{ dParamStr = AESUtil.decrypt(paramStr, AES_SECURTY); }catch (Exception e){ throw new Exception("解密失败!"); } log.info("解密得到字符串{}", dParamStr); String signature = SignUtil.sign(dParamStr, MD5_SALT); log.info("重新加密得到签名{}", signature); JSONObject jsonObject1 = JSONUtil.toJO(dParamStr); if (!jsonObject1.getString("signature").equals(signature)) { throw new Exception("签名不匹配!"); } return jsonObject1.toJSONString(); } private Mono processError(String message) { /*exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete();*/ log.error(message); return Mono.error(new Exception(message)); } ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, MyCachedBodyOutputMessage outputMessage) { return new ServerHttpRequestDecorator(exchange.getRequest()) { public HttpHeaders getHeaders() { long contentLength = headers.getContentLength(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); if (contentLength > 0L) { httpHeaders.setContentLength(contentLength); } else { httpHeaders.set("Transfer-Encoding", "chunked"); } return httpHeaders; } public Flux
getBody() { return outputMessage.getBody(); } }; }}

代码到这里就结束了,希望看到的朋友可以少走点弯路,少踩点坑。

 

转载地址:https://blog.csdn.net/yucaifu1989/article/details/105433195 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Spring Cloud Gateway(读取、修改 Request Body
下一篇:Typora入门:全网最全教程

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月03日 16时36分29秒