前后端分离下,Spring Boot 请求从发起到响应的完整执行流程

06-01 1609阅读

前后端分离下,Spring Boot 请求从发起到响应的完整执行流程以下是前后端分离架构下,Spring Boot 请求从发起到响应的完整执行流程,结合你提出的所有问题,按真实执行顺序和职责链条重新整理所有核心概念、结构、关键类、数据转换点和典型代码示例:


一、前端发起请求(步骤1-2)

关键组件:React/Vue + Axios + JSON

axios.get('/api/users', { headers: { Authorization: 'Bearer xxx' } });
  • 不会包含 JSON body(因 GET 请求规范所限)

  • 请求参数以 query param 附带,如 /api/users?active=true


    二、后端接收请求与过滤(步骤3)

    关键组件:Spring Security Filter Chain

    public class JwtAuthenticationFilter extends OncePerRequestFilter {
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
            String header = request.getHeader("Authorization");
            String token = header != null && header.startsWith("Bearer ") ? header.substring(7) : null;
            if (token != null && jwtUtil.validate(token)) {
                Authentication auth = jwtUtil.getAuthentication(token);
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
            chain.doFilter(request, response);
        }
    }
    
    • JWT 验证只发生在 Filter 中,不会进入 Controller 就已判定是否通过

    • 验证通过后构造 Authentication 对象放入 SecurityContext


      三、DispatcherServlet 分发请求(步骤4)

      核心作用:统一接收请求,协调执行链

      • DispatcherServlet 并不执行具体处理,只负责流程编排


        四、HandlerMapping 确定 Handler(步骤5)

        RequestMappingHandlerMapping:匹配@Controller + @RequestMapping 控制器方法
        
        • 负责查找哪个 Controller 的哪个方法应该处理这个请求

        • 构建好 HandlerExecutionChain(包含拦截器)


          五、HandlerAdapter 调用处理器(步骤6)

          RequestMappingHandlerAdapter:负责调用注解控制器方法
          
          • supports(Object handler) 方法确认适配器是否支持此处理器

          • 参数解析、类型转换、方法调用都由它完成


            六、Controller 执行业务分发(步骤7)

            @RestController
            @RequestMapping("/api/users")
            public class UserController {
                @Autowired
                private UserService userService;
                @GetMapping
                public ResponseEntity getUsers() {
                    List list = userService.getAllUsers();
                    return ResponseEntity.ok(list);
                }
            }
            
            • Controller 不应处理认证逻辑,而是专注于业务与 DTO 构造

            • 使用 ResponseEntity 是为了更灵活控制 HTTP 状态码与头部


              七、Service 层执行业务逻辑(步骤8)

              @Service
              public class UserServiceImpl implements UserService {
                  public List getAllUsers() {
                      List entities = userRepository.findAll();
                      return entities.stream().map(this::toDto).toList();
                  }
                  private UserDto toDto(User user) {
                      return new UserDto(user.getId(), user.getName(), user.getEmail());
                  }
              }
              
              • 接收 Entity 对象 → 转换为 DTO(数据传输对象)

              • 不应返回 ResponseEntity,这保持了关注点分离


                八、Repository 访问数据库(步骤9-11)

                @Repository
                public interface UserRepository extends JpaRepository {
                    List findByActiveTrue();
                }
                @Entity
                @Table(name = "users")
                public class User {
                    @Id
                    private Long id;
                    private String name;
                    private String email;
                }
                
                • DAO 实质上是 Repository 接口本身(即 Data Access Object)

                • Entity 是 ORM 框架(JPA/Hibernate)使用的 Java → 表 的映射结构

                • 从数据库返回的是 Entity 实例,非 DTO,非 DAO


                  九、响应流程(步骤12-17)

                  数据返回结构:

                  步骤返回对象类型
                  12Repository → ServiceEntity 实体类
                  13Service → ControllerDTO(如 UserDto)
                  14Controller → HandlerAdapterResponseEntity 或直接 DTO
                  15HandlerAdapter → DispatcherServlet包装为 ModelAndView(内部结构)
                  17DispatcherServlet → 前端JSON 数据(通过 HttpMessageConverter 序列化)

                  十、常见问题澄清汇总

                  ❓JWT是谁生成的?前端能编辑它吗?

                  • ❌ 前端不能生成 JWT,必须由后端签名生成

                  • ✅ JWT 中的 claim 字段(sub/iss/exp)由后端控制

                    ❓为什么需要 Authentication?不能直接验证放行?

                    • ✅ 因为权限注解(如 @PreAuthorize)等依赖 SecurityContextHolder 中的 Authentication 对象

                      ❓HandlerMapping vs HandlerAdapter 为什么都要有?

                      组件功能是否必须
                      HandlerMapping确定哪个 Controller 处理请求
                      HandlerAdapter执行该 Controller 的方法
                      • 二者实现了解耦:DispatcherServlet 不直接依赖 Controller 类型

                      • 实际开发可以注册自定义 Mapping/Adapter

                        ❓ResponseEntity vs DTO vs ResponseObject 区别?

                        类型

                        定义

                        用途

                        DTO

                        纯Java对象,字段只为数据交换

                        Service 返回给 Controller

                        ResponseEntity

                        Spring类,用于封装响应状态、头、体

                        Controller 返回给框架

                        自定义 ResponseObject

                        如 ApiResponse,封装统一格式

                        可选嵌入于 ResponseEntity 中

                        ✅ 不是必须使用 ResponseEntity,直接返回 DTO,Spring 也会自动序列化


                        建议实践结构总结

                        前端请求 → Filter链认证(JWT) → DispatcherServlet协调 → HandlerMapping确定Controller
                        → HandlerAdapter调用Controller方法 → Controller调用Service → Service调用Repository
                        → Repository返回Entity → Service转换为DTO → Controller包装为ResponseEntity
                        → 返回给前端(JSON)
                        

                        ✅ 先明确三个概念:

                        注解

                        用于

                        描述

                        @ExceptionHandler

                        控制器或异常处理类中的方法

                        声明某个方法用来处理特定类型异常

                        @ControllerAdvice

                        类级别

                        用于集中定义所有控制器的全局异常处理

                        @RestControllerAdvice

                        @ControllerAdvice + @ResponseBody

                        自动将返回值作为JSON响应


                        ✅ 情况分类:异常处理的三个层级

                        异常发生层

                        谁处理

                        示例

                        Controller层内部异常

                        当前 Controller 类中的 @ExceptionHandler 或 @ControllerAdvice

                        请求参数缺失、非法访问

                        Service层抛出业务异常

                        交由 Controller 接收并传播给 @ControllerAdvice

                        用户名重复、余额不足

                        Repository层抛出数据访问异常

                        Service 可以选择 catch/转义,也可以上抛

                        JPA抛出 DataIntegrityViolationException 等

                        ❓1. “用了@ExceptionHandler,为什么还需要@ControllerAdvice?”

                        • @ExceptionHandler 是方法级,@ControllerAdvice 是全局级的,集中管理多个Controller的异常处理 。所以两者不是“互相替代”,而是范围不同:ControllerAdvice 是容器,ExceptionHandler 是容器里的处理器方法


                          ❓2. 那为什么还说“Controller处理Service抛出的异常”?“Controller处理Service异常”指的是:“异常发生于Service层,但由Controller层抛出并触发了统一异常处理机制”。


                          ✅ 代码级举例(完整调用链)

                          ➤ 1. 自定义异常类:

                          ➤ 2. Service层抛出异常:

                          ➤ 3. Controller调用Service:

                          ➤ 4. 全局异常处理器:

                          @RestControllerAdvice
                          public class GlobalExceptionHandler {
                              @ExceptionHandler(UserAlreadyExistsException.class)
                              public ResponseEntity handleUserExists(UserAlreadyExistsException ex) {
                                  ApiError error = new ApiError(409, ex.getMessage());
                                  return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
                              }
                              @ExceptionHandler(Exception.class)
                              public ResponseEntity handleOther(Exception ex) {
                                  ApiError error = new ApiError(500, \"Internal server error\");
                                  return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
                              }
                          }
                          

                          ✅ 小结(极简结论):

                          问题结论
                          @ExceptionHandler 和 @ControllerAdvice 冲突吗?❌ 不冲突,前者方法级,后者类级,全局异常需要配合使用
                          Controller是否“处理”Service抛出的异常?✅ 表面上Controller收到异常,实则由 @ControllerAdvice 捕获
                          实际开发该怎么用?✅ 建议所有 Controller 异常集中交由 @RestControllerAdvice 来统一处理

                          ✅ 一、前后端通信中的数据结构与序列化处理

                          ❓1. 前端发送 GET 请求 /api/users,不做 JSON 清洗吗?后端收到的是什么?直接处理 JSON 吗?

                          • ✅ GET 请求不会带有 JSON 请求体(规范禁止),数据清洗体现在构造 Query 参数(如 /api/users?active=true)。

                          • ✅ 后端不会处理 JSON,而是通过 @RequestParam 解析 URL 查询参数。

                          • ✅ JSON 序列化只发生在 POST/PUT 请求体 或 响应数据 中。


                            ❓2. JSON 序列化 / 反序列化发生在哪一步?DispatcherServlet 负责吗?

                            • ✅ 反序列化(JSON → Java)发生在 HandlerAdapter 调用 Controller 方法前。

                            • ✅ 序列化(Java → JSON)发生在 Controller 方法返回后。

                            • ❌ DispatcherServlet 不负责 JSON 处理,它只负责请求转发。

                            • ✅ JSON 的处理由 HttpMessageConverter(默认使用 Jackson)完成。


                              ✅ 二、DAO / DTO 的职责与流程中的定位

                              ❓3. 什么是 DAO 和 DTO?图中的第 12~14 步分别返回的是什么?

                              • ✅ DAO(Data Access Object)是用于封装数据库访问逻辑的接口,如 UserRepository extends JpaRepository。

                              • ✅ DTO(Data Transfer Object)是前后端或多层之间传递数据的载体,如 UserDto。

                              • 图中:

                                • 第12步:DAO 返回的是实体类(Entity);

                                • 第13步:Service 转换为 DTO,返回给 Controller;

                                • 第14步:Controller 使用 ResponseEntity 作为响应,框架底层封装为 ModelAndView。


                                  ❓4. ResponseEntity 和 Model 有什么区别?第 15 步为什么是 ModelAndView?

                                  • ✅ ResponseEntity 用于前后端分离,返回完整 JSON 响应;

                                  • ✅ Model 是传统 MVC 模式中用于传数据给视图模板的结构;

                                  • ✅ ModelAndView 是 Spring MVC 底层用于封装所有结果的统一结构(即使你返回的是 ResponseEntity,框架也封装为 ModelAndView(null, body))。

                                  • ✅ 前后端分离时,开发者只用 ResponseEntity,无需直接接触 ModelAndView。


                                    ✅ 三、Spring Security 中的 JWT 验证机制

                                    ❓5. JWT 验证流程在 Spring Boot 中是怎样的?在哪一层?

                                    • ✅ JWT 验证发生在 FilterChain 阶段,通常在 OncePerRequestFilter 中实现;

                                    • ✅ 验证步骤:

                                      • 从请求 Header 获取 Authorization: Bearer ;

                                      • 验证签名、结构、过期时间;

                                      • 解析生成 Authentication;

                                      • 设置到 SecurityContextHolder;

                                      • 放行到 DispatcherServlet;

                                      • ❌ DispatcherServlet 和 Handler 不参与认证,只接收已验证请求。


                                        ❓6. JWT 是由前端编辑生成的吗?字段如 iss、sub、exp、roles 是前端决定的吗?

                                        • ❌ JWT 不能由前端生成;

                                        • ✅ JWT 是后端使用密钥生成的,包含的字段完全由后端控制;

                                        • ✅ 前端只是接收、存储并在请求中携带;

                                        • JWT 示例字段如 sub: userId, exp: timestamp, roles: ["ADMIN"] 都由后端代码设置。


                                          ❓7. 为什么 JWT 验证完还要构建 Authentication 对象?不能直接转发请求吗?

                                          • ✅ 构建 Authentication 的目的是让 Spring Security 安全机制生效:

                                            • 权限判断(如 @PreAuthorize)依赖 SecurityContext;

                                            • 日志、审计、日志追踪、用户上下文等都依赖它;

                                            • ❌ 如果跳过该步骤,系统将视为匿名用户,请求将不具备认证身份。


                                              ✅ 四、Spring Security 的方法级授权机制

                                              ❓8. @PreAuthorize 注解用在哪些类?在哪一步执行?为什么叫 Pre?看起来像是在认证前

                                              • ✅ @PreAuthorize 用于 Controller 或 Service 方法上,限制某角色、用户是否能执行该方法;

                                              • ✅ 执行时机是 在方法体执行之前,不是在登录认证之前;

                                              • ✅ 所谓“Pre”指的是在方法调用前进行权限判断;

                                              • ✅ 注解本质通过 AOP 拦截方法,依赖于 Authentication 已存在(由 Filter 中设置);

                                              • ❌ 如果没有 Authentication,@PreAuthorize 判断失效,默认拒绝访问。

                                                用法:

                                                @PreAuthorize("hasRole('ADMIN')")
                                                public void deleteUser(Long id) { ... }
                                                @PreAuthorize("#userId == authentication.name")
                                                public void updateUser(Long userId, UserDto dto) { ... }
                                                

                                                ✅ 总结关键词表

                                                关键词解释
                                                DTO传输数据结构体,跨层/跨系统使用
                                                DAO数据访问接口,用于封装数据库操作
                                                ResponseEntity用于返回 JSON 响应体的 Spring 结构
                                                ModelAndViewSpring MVC 内部统一封装结构
                                                JWTJSON Web Token,认证令牌,由后端生成
                                                AuthenticationSpring Security 中用于表示认证用户的对象
                                                SecurityContextHolder保存当前请求上下文的认证信息
                                                @PreAuthorize方法级授权注解,执行方法前做权限判断

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码