您现在的位置是:首页 >学无止境 >【SpringMVC】| 拦截器 | 跨域请求 | 原理详解 | 代码实操网站首页学无止境

【SpringMVC】| 拦截器 | 跨域请求 | 原理详解 | 代码实操

狮子也疯狂 2023-07-24 00:00:06
简介【SpringMVC】| 拦截器 | 跨域请求 | 原理详解 | 代码实操

一. 🦁 前言

Spring MVC 是 Spring 框架的一部分,主要用于构建 Web 应用程序和 RESTful 服务。Spring MVC 拦截器是一种在请求到达控制器之前或响应返回视图之前对请求进行处理的机制。它可以对请求进行拦截和修改,比如在请求中添加一些头信息、记录请求日志、进行身份验证等。跨域请求则是指在浏览器中发起的与当前页面所在域名不同的请求,例如从前端的一个页面向后端的另一个域名发起 AJAX 请求。为了保证安全性与可控性,通常需要对跨域请求进行一些限制和处理。Spring MVC 提供了一些用于处理跨域请求的解决方案,例如使用 CORS 或 JSONP 等。

二. 🦁 拦截器 & 跨域请求

1. 拦截器

image-20230422092510838

SpringMVC的拦截器(Interceptor)也是AOP思想的一种实现方式。它与Servlet的过滤器(Filter)功能类似,主要用于拦截用户的

请求并做相应的处理,通常应用在权限验证记录请求信息的日志判断用户是否登录等功能上。

Ⅰ. 拦截器和过滤器(Filter)的区别

  • 拦截器是SpringMVC组件,而过滤器是Servlet组件。

  • 拦截器不依赖Web容器,过滤器依赖Web容器(Java EE 的组件)。

  • 拦截器只能对控制器请求起作用,而过滤器则可以对所有的请求起作用。

  • 拦截器可以直接获取IOC容器中的对象,而过滤器就不太方便获取

Ⅱ. 拦截器的使用步骤

tips:

咱们在学SpringMVC时,肯定是通过配置文件来配置拦截器的,现在狮子使用Springboot来搭建SpringMVC,就不需要写配置文件那么繁琐!!!可以使用WebMvcConfigurer接口来配置拦截器链,从而替代Spring MVC中的拦截器配置文件(mvc-dispatcher-servlet.xml,详细流程如下:

1. 创建SpringBoot项目,添加Spring Web依赖
2. 创建控制器方法
@RequestMapping("/m1")
public String m1(){
  System.out.println("控制器方法");
  return "result";
}
3. 创建拦截器类

该类实现HandlerInterceptor接口,需要重写三个方法:

preHandle:请求到达Controller前执行的方法,返回值为true通过拦截器,返回值为false被拦截器拦截。

postHandle:跳转到JSP前执行的方法。

afterCompletion:跳转到JSP后执行的方法。

// 拦截器类
public class MyInterceptor implements HandlerInterceptor {
  // 请求到达Controller前执行
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    System.out.println("请求到达Controller前");
    // 如果return false则无法到达Controller
    return true;
   }


  // 跳转到JSP前执行,此时可以向Request域添加数据
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    System.out.println("跳转到JSP前");
    request.setAttribute("name","百战");
   }


  // 跳转到JSP后执行,此时已经不能向Request域添加数据
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    System.out.println("跳转到JSP后");
    request.setAttribute("age",10);
   }
}

4. 编写JSP页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>结果</title>
  </head>
  <body>
    <h3>name:${requestScope.name}</h3>
    <h3>age:${requestScope.age}</h3>
  </body>
</html>
5. 配置Interceptor核心配置类
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserInterceptor())	// addInterceptor()方法添加一个拦截器
                .addPathPatterns("/campus/**")			// addPathPatterns()方法指定拦截的路径
                .addPathPatterns("/edu/**")
                .addPathPatterns("/info/**")
                .addPathPatterns("/pos/**")
                .addPathPatterns("/project/**")
                .addPathPatterns("/project/**");
        		.excludePathPatterns("/login"); // 排除/login请求,   excludePathPatterns()方法则指定不拦截的路径
    }
}
6. 拦截器链与执行顺序

image-20230422095255645

如果一个URL能够被多个拦截器所拦截,全局拦截器最先执行,其他拦截器根据配置文件中配置的从上到下执行。

tips:

  • preHandle()顺序执行,postHandle()、afterComletion()逆序执行。

  • 只要有一个preHandle()拦截,后面的preHandle(),postHandle()都不会执行。

  • 只要相应的preHandle()放行,afterComletion()就会执行。

Ⅲ. 实操——拦截器过滤敏感词案例

在Spring Boot中,配置拦截器链可以通过实现WebMvcConfigurer接口来完成。

  1. 创建一个WordFilter类,实现HandlerInterceptor接口,在preHandle方法中对请求参数中的敏感词进行过滤
@Component
public class WordFilter implements HandlerInterceptor {

    @Autowired
    private WordService wordService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String wordString = request.getParameter("words"); // 假设敏感词参数名为"words"
        if (wordString != null) {
            String[] words = wordString.split(",");
            List<String> sensitiveWords = wordService.getAllWords(); // 获取所有敏感词
            for (String word : words) {
                if (sensitiveWords.contains(word)) { // 判断是否为敏感词
                    // 如果是敏感词,则输出提示信息并返回false,终止请求
                    response.setContentType("text/html;charset=UTF-8");
                    PrintWriter out = response.getWriter();
                    out.print("<script>alert('请求中包含敏感词 " + word + ",请修改后重试!');</script>");
                    out.flush();
                    out.close();
                    return false;
                }
            }
        }
        // 如果请求中没有敏感词,则返回true,继续请求
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // do nothing
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // do nothing
    }
}
  1. 创建一个WordService类,用于获取所有敏感词。这里假设将敏感词保存在一个List中。在实际应用中,可以将敏感词保存在数据库中,并提供相关的增删查改接口。
@Service
public class WordService {

    private static final List<String> WORD_LIST = Arrays.asList("敏感词1", "敏感词2", "敏感词3");

    public List<String> getAllWords() {
        return WORD_LIST;
    }
}
  1. WebConfig类中注册拦截器WordFilter
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private WordFilter wordFilter;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(wordFilter).addPathPatterns("/**");
    }
}

到此为止,敏感词过滤的示例已经完成

2. 跨域请求

同源策略是浏览器的一个安全功能。同源,指的是两个URL的协议,域名,端口相同。浏览器出于安全方面的考虑,不同源的客户

端脚本在没有明确授权的情况下,不能读写对方资源。(即前端策略,跟后端没啥关系)

image-20230422102723704

当请求URL的协议、域名、端口三者中任意一个与当前页面URL不同时即为跨域。浏览器执行JavaScript脚本时,会检查当前请求是否

同源,如果不是同源资源,就不会被执行。

哪些不受同源策略限制:

  • 页面中的 跳转、表单提交不会受到同源策略限制的。

  • 静态资源引入也不会受到同源策略限制。如嵌入到页面中的

Ⅰ.控制器接收跨域请求

image-20230422103002043

SpringMVC提供了注解**@CrossOrigin**解决跨域问题。

案例 一

在Spring Boot中,可以通过添加一个WebMvcConfigurer bean来配置跨域请求。以下是一个示例:

  1. 首先,在application.properties中添加以下配置:
# 允许跨域请求的域名(*表示允许任何域名)
spring.mvc.cross-origin.allowed-origins=*
# 允许跨域请求的HTTP方法
spring.mvc.cross-origin.allowed-methods=GET,POST,PUT,DELETE
# 允许跨域请求的HTTP头部信息
spring.mvc.cross-origin.allowed-headers=*
# 是否允许发送cookie
spring.mvc.cross-origin.allow-credentials=true
  1. 创建一个WebMvcConfigurer bean并重写addCorsMappings方法,设置跨域请求规则。例如:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
 
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 匹配所有路径
                .allowedOrigins("*") // 允许跨域请求的域名(*表示允许任何域名)
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许跨域请求的HTTP方法
                .allowedHeaders("*") // 允许跨域请求的HTTP头信息
                .allowCredentials(true); // 是否允许发送cookie
    }
}

以上代码中,通过addMapping方法来设置需要允许跨域的路径,使用allowedOrigins方法允许跨域请求的域名,使用allowedMethods方法允许跨域请求的HTTP方法,使用allowedHeaders方法允许跨域请求的HTTP头信息,使用allowCredentials方法设置是否允许发送cookie。

需要注意的是,如果在WebMvcConfigurer bean中配置了跨域请求规则,就不需要再在Controller层添加跨域请求注解了。例如,以下代码中就不需要使用@CrossOrigin注解了:

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, world!";
    }
}

到此为止,一个通过配置WebMvcConfigurer bean实现跨域请求的示例就完成了。

方案二

在Spring Boot中,可以使用@CrossOrigin注解来解决跨域请求,具体使用方法如下:

  1. 在Controller类或方法上添加@CrossOrigin注解。例如:
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "*", allowedHeaders = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE}, allowCredentials = "true")
public class ApiController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, world!";
    }
}

以上代码中,@CrossOrigin注解的参数如下:

  • origins:允许跨域请求的域名,可以使用通配符*表示允许任何域名。
  • allowedHeaders:允许跨域请求的HTTP头信息。
  • methods:允许跨域请求的HTTP方法。
  • allowCredentials:是否允许发送cookie。
  1. 如果需要在多个Controller类或方法上使用相同的跨域请求规则,也可以在WebMvcConfigurer bean中配置全局的跨域请求规则。例如:
@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 匹配所有路径
                .allowedOrigins("*") // 允许跨域请求的域名(*表示允许任何域名)
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许跨域请求的HTTP方法
                .allowedHeaders("*") // 允许跨域请求的HTTP头信息
                .allowCredentials(true); // 是否允许发送cookie
    }
}

以上代码中,通过addMapping方法来设置需要允许跨域的路径,使用allowedOrigins方法允许跨域请求的域名,使用allowedMethods方法允许跨域请求的HTTP方法,使用allowedHeaders方法允许跨域请求的HTTP头信息,使用allowCredentials方法设置是否允许发送cookie。

需要注意的是,如果在WebMvcConfigurer bean中配置了全局的跨域请求规则,就不需要在Controller层添加@CrossOrigin注解了。例如,以下代码中就不需要使用@CrossOrigin注解了:

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, world!";
    }
}

到此为止,一个通过@CrossOrigin注解实现跨域请求的示例就完成了。

三. 🦁 最后

到这里,SpringMVC专栏更新完成啦,欢迎小伙伴们关注学习哦!!!一起加油😄

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。