Spring Cloud Gateway -- 修改RequestBody和Header

╰+哭是因爲堅強的太久メ 2022-04-25 10:08 1292阅读 0赞

Spring Cloud Gateway — 修改RequestBody和Header

  • 前言
  • 读取和修改RequestBody
  • 修改Header
  • 添加路由

前言

目前项目有个需求,前端POST请求需要以xml形式传输,后端接口有些返回的是JSON格式有些返回的XML格式并且由于网络架构的需求,需要一个中间平台来处理这些请求。最终觉得利用Spring Cloud Gateway来实现。前端统POST请求统一用AJAX发送请求,中间平台将POST转换成XML形式,并且对相应的如果是xml形式的数据转成成JSON的格式进行返回。

读取和修改RequestBody

读取RequestBody的方法。
本人的一点猜测:这个方法可能是有缺陷的,因为在读取ResponseBody的时候由于后台的返回的数据量很大,好像是分了好几次发送,需要将其拼装在一起之后在做处理(后面的博客会讲到的)。故而猜测这里应该是同样的道理,不过由于请求参数不会很多,所有先不管后面有时间在进行测试。(后面确实发现有问题 —解决办法)

  1. /** * 获取请求体中的字符串内容 * @param serverHttpRequest * @return */
  2. private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest){
  3. //获取请求体
  4. Flux<DataBuffer> body = serverHttpRequest.getBody();
  5. StringBuilder sb = new StringBuilder();
  6. body.subscribe(buffer -> {
  7. byte[] bytes = new byte[buffer.readableByteCount()];
  8. buffer.read(bytes);
  9. DataBufferUtils.release(buffer);
  10. String bodyString = new String(bytes, StandardCharsets.UTF_8);
  11. sb.append(bodyString);
  12. });
  13. return sb.toString();
  14. }

对请求的方式进行判断,之后将数据转换成XML形式,并且需要重新传递。
重点

  1. 无论你修改了什么东西,都是需要new ServerHttpRequestDecorator 这个对象,并且调用你相对应的方法,例如我这边改了body就需要重写getBody这个方法。大家可以具体看看这个ServerHttpRequestDecorator的提供的方法就行了。
  2. 修改了Body 还需要修改CONTENT_LENGTH(下面会说的)

    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

    1. ServerHttpRequest oldRequest= exchange.getRequest();
    2. URI uri = oldRequest.getURI();
    3. if("POST".equalsIgnoreCase(oldRequest.getMethodValue())) {
    4. Object requestBody = resolveBodyFromRequest(oldRequest);
    5. String xml = "";
    6. if(requestBody != null){
    7. xml = resolveBodyToXML(requestBody.toString());
    8. }
    9. //把request重新包装,继续传递
    10. ServerHttpRequest newRequest = null;
    11. try {
    12. byte[] bytes = URLEncoder.encode(xml, "UTF-8").replaceAll("\\+", "%20").getBytes(StandardCharsets.UTF_8);
    13. DataBuffer bodyDataBuffer = stringBuffer(new String(bytes));
    14. Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
    15. newRequest = oldRequest.mutate().uri(uri).build();
    16. newRequest = new ServerHttpRequestDecorator(newRequest) {
    17. @Override
    18. public Flux<DataBuffer> getBody() {
    19. return bodyFlux;
    20. }
    21. };
    22. } catch (UnsupportedEncodingException e) {
    23. e.printStackTrace();
    24. }
    25. return chain.filter(exchange.mutate().request(newRequest).build());
    26. }else{
    27. return chain.filter(exchange);
    28. }
    29. }

修改Header

和修改Body同理。修改CONTENT_TYPE和CONTENT_LENGTH
我是把同一个代码拆开了,为了看的清楚一些。大家把他们拼起来就好了

  1. // 定义新的消息头
  2. HttpHeaders headers = new HttpHeaders();
  3. headers.putAll(exchange.getRequest().getHeaders());
  4. // 由于修改了传递参数,需要重新设置CONTENT_LENGTH,长度是字节长度,不是字符串长度
  5. int length = bytes.length;
  6. headers.remove(HttpHeaders.CONTENT_LENGTH);
  7. headers.setContentLength(length);
  8. headers.set(HttpHeaders.CONTENT_TYPE, "text/xml");
  9. newRequest = new ServerHttpRequestDecorator(newRequest) {
  10. @Override
  11. public HttpHeaders getHeaders() {
  12. return headers;
  13. }
  14. };

添加路由

这个就比较平常了

  1. @EnableAutoConfiguration
  2. @Configuration
  3. public class ApiLocator {
  4. @Autowired
  5. private RequestFilter requestFilter;
  6. @Bean
  7. public RouteLocator myRoutes(RouteLocatorBuilder builder) {
  8. List list = new ArrayList();
  9. list.add(requestFilter);
  10. RouteLocatorBuilder.Builder routes = builder.routes();
  11. RouteLocatorBuilder.Builder serviceProvider = routes
  12. .route("route3",
  13. r -> r.path(SERVICE)
  14. .filters(f -> {
  15. f.filters(list);
  16. return f;
  17. }).uri(URI));
  18. RouteLocator routeLocator = serviceProvider.build();
  19. return routeLocator;
  20. }
  21. }

发表评论

表情:
评论列表 (有 0 条评论,1292人围观)

还没有评论,来说两句吧...

相关阅读