首页 > 编程语言 >【SpringBoot 编程】在SpringBoot中拦截修改请求Body的2种正确方式

【SpringBoot 编程】在SpringBoot中拦截修改请求Body的2种正确方式

时间:2024-12-09 15:21:34浏览次数:11  
标签:Body body 拦截器 return SpringBoot 编程 new public 请求

环境:SpringBoot3.2.5

1. 简介

修改请求Body内容的需求源于多种场景,其中最重要的是数据预处理和安全性考虑。在Web应用中,客户端发送的请求数据可能不符合后端服务的直接处理要求,如格式不匹配、不文明用语、数据不完整或包含敏感信息。通过修改请求Body,可以在数据到达Controller之前进行必要的格式化、验证、脱敏等处理,确保数据的准确性和安全性。同时这促进了松散耦合,大大减少了开发工作量。

接下来我将通过2种方式来实现如何在请求到底Controller之前进行请求body的修改。

2. 实战案例

2.1 准备接口

需要先准备一个后端接口,用来接收请求body内容。

public class Article {
  private String title ;
  private String content ;
  // getters, setters
}
// 接口
@RestController
@RequestMapping("/modifybody")
public class ModifyBodyController {

  @PostMapping
  public Article save(@RequestBody Article article) {
    return article ;
  }
}

接口定义非常简单,并没有任何的其它处理。接下来将基于该接口实现在不修改Controller接口的前提下,修改请求中title或者是content中的特殊字符。

2.2 基于Filter实现

过滤器是解决在任何 Servlet 容器中运行的应用程序的这些通用问题的最佳选择。
下图是过滤器的工作原理图:

理解了Filter的工作原理后,接下来定义一个Filter,该Filter作用是用来转义 HTTP 请求正文中的所有 HTML 字符,以防止 XSS 攻击。

过滤器定义

@Component
@Order(1)
public static class EscapeHtmlFilter implements Filter {
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
    filterChain.doFilter(new EscapeHtmlRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
  }
}

注意,这里我们重新包装了HttpServletRequest对象,否则将会出现Request Body只能读取一次的情况。

public static class EscapeHtmlRequestWrapper extends HttpServletRequestWrapper {

  private String body = null;
  public EscapeHtmlRequestWrapper(HttpServletRequest request) throws IOException {
    super(request);
    this.body = HtmlUtils.escapeHtml(request);
  }
  public ServletInputStream getInputStream() throws IOException {
    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
    ServletInputStream servletInputStream = new ServletInputStream() {
      @Override
      public int read() throws IOException {
        return byteArrayInputStream.read();
      }
      // 这里还有其它的方法,默认即可
    };
    return servletInputStream;
  }
  public BufferedReader getReader() {
    try {
      return new BufferedReader(new InputStreamReader(this.getInputStream()));
    } catch (IOException e) {}
    return null;
  }
}

以上就完成了关键的代码,接下来就可以进行测试了

正确的将<script>标签删除了。

2.3 通过AOP实现

通过RequestBodyAdvice 接口和注解 @RestControllerAdvice可用于所有 REST 控制器。利用它们在 HTTP 请求到达控制器之前转义 HTML 字符:

@RestControllerAdvice
public class EscapeHtmlBodyAdvice implements RequestBodyAdvice {
  public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
      Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
    InputStream is = inputMessage.getBody() ;
    return new HttpInputMessage() {
      public InputStream getBody() throws IOException {
        return new ByteArrayInputStream(HtmlUtils.escapeHtml(is).getBytes(StandardCharsets.UTF_8)) ;
      }
      public HttpHeaders getHeaders() {
        return inputMessage.getHeaders() ;
      }
    } ;
  }

  public boolean supports(MethodParameter methodParameter, Type targetType,
      Class<? extends HttpMessageConverter<?>> converterType) {
    return true ;
  }

  public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
      Class<? extends HttpMessageConverter<?>> converterType) {
    return body ;
  }

  public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
      Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
    return body ;
  }
}

注:这并非真的AOP技术(并没有产生代理),只是在读取数据之前执行了该操作。

如果有必要你可以在上面的supports放中进行条件判断,只有符合条件的才进行处理。

以上是正确的2种方式实现修改Request Body内容。是否还有其它技术实现呢?拦截器是可以呢?接下来我们通过拦截器的方式进行尝试修改内容。

2.4 使用拦截器

拦截器可以拦截传入的 HTTP 请求,并在控制器处理这些请求之前对其进行处理。拦截器有多种用途,如身份验证、授权、日志记录和缓存。此外,拦截器是 Spring MVC 框架的特有功能,它们可以访问 Spring ApplicationContext,如下是拦截器的工作原理:

DispatcherServlet 会将 HTTP 请求转发给拦截器。此外,在处理之后,拦截器可以将请求转发给控制器或拒绝该请求。

public static class EscapeHtmlRequestInterceptor implements HandlerInterceptor {
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    EscapeHtmlRequestWrapper htmlEscapeRequestWrapper = new EscapeHtmlRequestWrapper(request);
    // 其实写到这你就应该想到这里的EscapeHtmlRequestWrapper 是如何传递下去的呢?
    // 这里的返回值仅仅是boolean类型是否要继续请求而已。
    // 这里我们姑且像下面这样调用父类的方法吧
    return HandlerInterceptor.super.preHandle(htmlEscapeRequestWrapper, response, handler) ;
  }
}
// 注册拦截器
@Component
public class WebMvcConfiguration implements WebMvcConfigurer {
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new EscapeHtmlRequestInterceptor()).addPathPatterns("/**");
  }
}

测试请求

控制台抛出了错误,客户端返回了400状态码。

这也就说明了,通过拦截器是无法实现修改Request Body内容的

原创 Springboot实战案例锦集

标签:Body,body,拦截器,return,SpringBoot,编程,new,public,请求
From: https://www.cnblogs.com/o-O-oO/p/18595011

相关文章

  • 基于springboot+vue实现的项目评审系统 (源码+L文+ppt)4-116
    摘 要相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低运营人员成本,实现了项目评审系统的标准化、制度化、程序化的管理,有效地防止了项目评审的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正项目信息、评审结果、项目申报等信息。课题主要采......
  • 基于springboot+vue实现的剧本杀管理系统(源码+L文+ppt)4-114
      摘 要剧本杀管理系统是一个综合性平台,为剧本杀游戏爱好者、创作者及商家提供多方位服务。系统具备用户账号管理、剧本分类、预约、评价和论坛交流等核心功能。通过这个平台,用户可以便捷地浏览各类剧本信息,根据兴趣和时间安排进行预约,同时在游戏结束后对体验进行反馈。......
  • 基于springboot+vue实现的项目评审系统 (源码+L文+ppt)4-116
      摘 要相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低运营人员成本,实现了项目评审系统的标准化、制度化、程序化的管理,有效地防止了项目评审的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正项目信息、评审结果、项目申报等信息。课题主......
  • JUC 多线程并发编程
    一、基本概念1.进程与线程进程(Process):计算机中正在运行的程序的实例,是操作系统分配资源的基本单位。每个进程拥有自己的内存空间、文件描述符、数据栈等。线程(Thread):进程中的一个执行单元。一个进程中至少有一个线程,通常称为主线程。线程是CPU调度和执行的最小单位。线程共......
  • 【Java编程】Java 中的 Function:让转换逻辑更灵活
    Function<T,R>是Java中一个重要的函数式接口,适用于将一个输入转换为一个输出的场景。通过Function,我们可以将复杂的转换逻辑抽象化,提升代码的灵活性和可读性。今天,让我们探讨Function在开发中的妙用,让代码更简洁、模块化!1.Function基础:简化转换逻辑Function的核心方法......
  • 【Java编程】如果我自己写一个 String 类,会不会和 Java 内置的 String 类冲突呢?
    在Java中,String类几乎是最基础、最常用的类之一,所以如果我们自己写一个名为String的类,很容易和Java内置的String类产生冲突。这种冲突可能会导致代码错误,甚至让代码运行不符合预期。本文将详细探讨这个问题,并解释如何避免这些冲突。1.直接在代码中定义一个String类......
  • 算法编程题-区间列表的交集、飞机座位分配概率
    算法编程题-区间列表的交集、飞机座位分配概率区间列表的交集原题描述思路简述代码实现复杂度分析飞机座位分配概率原题描述思路简述代码实现复杂度分析摘要:本文将介绍两道LeetCode原题,一道是区间列表交集,另外一道则是飞机座位分配概率,实质上是一道常考的智力题。......
  • C语言编程1.22小L的难题
    题目描述最近,小L遇到了一道难题,请你帮帮他。给出n个数,请找出这个序列的任意两个不同的数第二小的差值。ai��和aj��的差值定义为∣ai−aj∣∣��−��∣,即两个数差的绝对值,其中i�和j�互不相同。(第二小即从小到大排序之后的第二个数字)输入格式第一行为一个正整数n(3≤n≤105)�(3≤�≤105),代表数......
  • SpringBoot 广场舞团:多元舞步,演绎广场风情画
    3系统分析3.1系统可行性分析3.1.1经济可行性由于本系统是作为毕业设计系统,且系统本身存在一些技术层面的缺陷,并不能直接用于商业用途,只想要通过该系统的开发提高自身学术水平,不需要特定服务器等额外花费。所有创造及工作过程仅需在个人电脑上就能实现,使用到的软件大多......
  • 【从0带做】基于协同过滤算法的springboot+vue的煤矿员工健康管理系统的设计与实现 【
    ✍✍计算机编程指导师⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java实战|SpringBoot/SSMPython实战项目|Django微信小程......