[Java]SpringBoot登录认证流程详解

news2024/11/15 17:46:12

登录认证

登录接口

1.查看原型

2.查看接口

3.思路分析

登录核心就是根据用户名和密码查询用户信息,存在则登录成功, 不存在则登录失败

4.Controller

@Slf4j
@RestController
public class LoginController {

    @Autowired
    private EmpService empService;

    /**
     * 登录的方法
     *
     * @param emp
     * @return
     */
    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        log.info("员工登录:{}", emp);
        Emp e = empService.login(emp);
        return e != null ? Result.sucess():Result.error("用户名或密码错误");
    }
}

5.Server

/**
 * 员工管理
 */
public interface EmpService {

    /**
     * 员工登录
     * @param emp
     */
    Emp login(Emp emp);
}
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;
    
    /**
     * 员工登录
     * @param emp
     * @return
     */
    @Override
    public Emp login(Emp emp) {
        return empMapper.getByUsernameAndPassword(emp);
    }
}

6.Mapper

/**
 * 员工管理
 */
@Mapper
public interface EmpMapper {

    /**
     * 根据用户名和密码查询账户信息
     * @param emp
     * @return
     */
    @Select("select * from emp where username = #{username} and password = #{password}")
    Emp getByUsernameAndPassword(Emp emp);

}

7.接口测试

登录校验

前端的所有请求, 都需要经过登录判断, 登录了进行正常操作, 没登录则返回错误信息, 让用户去登录页

会话跟踪

会话: 用户打开浏览器,访问web服务器的资源,会话建立,直到一方断开连接,会话结束, 在一次会话中, 可以包含多次请求和响应

会话跟踪: 一种维护浏览器状态的方法, 服务器需要识别多次请求是否来自同一浏览器, 以便在同一次会话的多次请求间共享数据

Cookie

客户端会话跟踪技术

  1. 优点:
  • HTTP协议支持的技术
  • 服务器返回Cookie / 浏览器保存Cookie / 客户端携带Cookie 都是自动完成的
  1. 缺点:
  • 移动端APP无法使用Cookie
  • 不安全, 用户可以自己禁用Cookie

  • Cookie不能跨域
  1. 当前地址和请求地址的 协议, 域名和端口 出现不同, 就形成了跨域

示例

@Slf4j
@RestController
public class SessionController {
   //设置Cookie
    @GetMapping("/c1")  
    public Result cookie(HttpServletResponse response){
        //通过HttpServletResponse获取响应对象
        //设置Cookit的name和value
        response.addCookie(new Cookie("login_username","itheima")); 
        return Result.success();
    }

    //获取Cookie
    @GetMapping("/c2")
    public Result cookie2(HttpServletRequest request){
        //获取所有的Cookie
        Cookie[] cookies = request.getCookies();  
        for (Cookie cookie : cookies) {
            if(cookie.getName().equals("login_username")) {  
                //找到name为login_username的Cookie
                System.out.println("login_username:" + cookie.getValue());
            }
        }

        return Result.success();
    }
}
  1. 后端只要设置了cookie, hppt就会自动在响应头的Set-Cookie属性中携带cookie信息

  1. 浏览器解析http时, 如果发现了Set-Cookie信息, 就会把信息自动储存在本地

  1. 当下次请求时, 就会在请求头的Cookie属性中自动携带该cookie信息

Session

服务端会话跟踪技术

  1. Session是基于Cookie实现的
  • Cooike直接把数据存储在浏览器, 不安全
  • Session是把Seeion ID存在在浏览器, 数据存储在服务器
  1. 优点: 数据存储在服务端, 安全
  2. 缺点:
  • Session基于Cookie实现,也继承了其缺点
  • 服务器集群环境下无法直接使用Session

示例

@Slf4j
@RestController
public class SessionController {

    // 往HttpSession中存储值
    @GetMapping("/s1")
    public Result session1(HttpSession session) {
        log.info("HttpSession-s1:{}", session.hashCode());
        //往session中存储值
        session.setAttribute("loginUser", "tom");  
        return Result.success();
    }
    
    // 从HttpSession中获取值
    @GetMapping("/s2")
    public Result session2(HttpServletRequest request) {
        HttpSession session = request.getSession();
        log.info("HttpSession-s2:{}", session.hashCode());
        //从session中获取数据
        Object loginUser = session.getAttribute("loginUser");  
        log.info("loginUser:{}", loginUser);
        return Result.success(loginUser);
    }
}
  1. 后端只要设置了Session, hppt就会自动在响应头的Set-Cookie属性中携带Session ID信息

  1. 浏览器解析http时, 如果发现了Set-Cookie信息, 就会把信息自动储存在本地

  1. 当下次请求时, 就会在请求头的Cookie属性中自动携带该Session ID信息

JWT令牌

介绍

全称 JSON Web Token, 定义了一种简洁的, 自包含的格式, 用于在通信双方以JSON数据格式安全的传输信息, 由于数字签名的存在, 这些信息是可靠的

  1. 官网: JSON Web Tokens - jwt.io
  2. 执行流程
  • 登录成功后, 生成令牌, 响应给前端, 前端保存起来
  • 前端的后续请求, 都携带JWT令牌
  • 后端在处理请求之前, 先校验令牌, 再处理业务
  1. 优缺点
  • 支持PC/移动端/小程序
  • 解决集群环境下的认证问题
  • 减轻服务器存储压力
  • 需要自己实现

JWT令牌本质是JSON对象, JSON对象储存数据, 经过Base64编码后, 在拼接上数字签名就形成了JWT令牌

  1. Base64: 是一种基于64个可打印字符(A-Z a-z 0-9 + /) 来表示二进制数据的编码方式
生成与校验
// JWT依赖
<dependency>
       <groupId>io.jsonwebtoken</groupId>
       <artifactId>jjwt</artifactId>
       <version>0.9.1</version>
</dependency>
@Test
public void testGenJwt(){
    Map<String,Object> claims = new HashMap<>();
    claims.put("id",1);
    claims.put("name","tom");

    // 生成JWT令牌
    String jwt = Jwts.builder()
         .signWith(SignatureAlgorithm.HS256,"itheima")  //指定签名算法
         .setClaims(claims)  //自定义内容(载荷)
         .setExpiration(new Date(System.currentTimeMillis()+3600*1000))  //设置有效期为1H
         .compact();
        System.out.println(jwt);
}
@Test
public void testParseJWT(){
    // 解析JWT令牌
    Claims claims = Jwts.parser()
         .setSigningKey("itheima")
         .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY5NjE0OTc2Nn0.7-rlCqZQ1XssTdNOM2os0s-mpuKHzUkwFWtsvMOlalY")
         .getBody();
    System.out.println(claims);
}
  1. JWT校验时使用的签名秘钥, 必须和生成JWT令牌时使用的秘钥配套
  2. 如果JWT令牌解析时报错, 说明JWT令牌被篡改 或者 失效了
登录校验-下发令牌

引入jwt依赖

// JWT依赖
<dependency>
       <groupId>io.jsonwebtoken</groupId>
       <artifactId>jjwt</artifactId>
       <version>0.9.1</version>
</dependency>

引入jwt工具类

public class JwtUtils {

    //指定签名秘钥
    private static String signKey = "itheima";
    //指定过期时间(12h)
    private static Long expire = 43200000L;

    /**
     * 生成JWT令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @return
     */
    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.HS256, signKey)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
}

生成jwt令牌, 并返回给前端

@Slf4j
@RestController
public class LoginController {

    @Autowired
    private EmpService empService;

    /**
     * 登录的方法
     *
     * @param emp
     * @return
     */
    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        log.info("员工登录:{}", emp);
        Emp e = empService.login(emp);
        //登录成功,生成jwt令牌,并下发令牌
        if(e!=null) {
            //把用户信息存入Map集合
            Map<String,Object> claims = new HashMap<>();
            claims.put("id",e.getId());
            claims.put("name",e.getName());
            claims.put("username",e.getUsername());
            //生成jwt令牌
            String jwt = JwtUtils.generateJwt(claims); //jwt令牌包含了用户信息
            // 下发令牌
            return Result.success(jwt);
        }

        //登录失败,返回错误信息
        return Result.error("用户名或密码错误");
    }
}

接口测试

过滤器

快速入门

filter过滤器是 javaWeb 三大组件( Servler / Filter / Listener )之一

  1. 过滤器可以拦截请求, 从而实现特殊功能
  2. 过滤器一般完成一些通用操作, 比如登录校验, 统一编码处理, 敏感字处理等

定义过滤器: 定义一个类, 实现Filter接口, 重写其所有方法

// 设置拦截请求的路径
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
    @Override 
    public void init(FilterConfig filterConfig) throws ServletException {
        //初始化的方法,服务器启动时只调用一次
        System.out.println("服务器启动了");
        Filter.super.init(filterConfig);
    }
    
    @Override 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 拦截到请求之后调用,调用多次
        System.out.println("拦截到请求了");
        // 设置放行, 不放行前端拿不到响应结果
        filterChain.doFilter(servletRequest,servletResponse);
        // 放行后的代码执行完, 还会回到拦截器
        System.out.println("放行后的逻辑");
    }
    
    @Override 
    public void destroy() {
        //销毁的方法,服务器关闭时只调用一次
        System.out.println("服务器关闭了");
        Filter.super.destroy();
    }
}
  1. 注意Filter是 javax.servlet 下的包
  2. 实际业务中, init 方法和 destroy方法不需要重写, 使用默认实现即可

配置过滤器: 过滤器是JavaWeb组件, 不是Springboot组件, 所以需在再启动类进行配置, 才能生效

//开启对servlet组件的支持
@ServletComponentScan 
@SpringBootApplication
public class TliasWebManagementApplication {

    public static void main(String[] args) {
        SpringApplication.run(TliasWebManagementApplication.class, args);
    }

}
详解

拦截器的执行流程

  1. 请求被拦截后, 先执行放行前的逻辑, 符合条件放行
  2. 方形后访问资源, 资源访问完成后还会回到过滤器中
  3. 回到过滤器后, 会执行过滤器放行后的逻辑

根据需求, 设置过滤器器的拦截路径

过滤器链: 一个web应用中, 可以配置多个过滤器,多个过滤器形成过滤器链

  1. 顺序: 定义多个过滤器之后, 过滤器生效的优先级, 是按照过滤器类名(字符串)的自然排序
登录校验-Filter

使用过滤器完成前端请求的登录校验

  1. 除了登录请求, 所有的请求都要进行令牌校验
  2. 拦截请求之后, token存在并且通过校验, 才能继续访问资源, 否则返回登录错误

登录校验实现的步骤

// 登录校验过滤器
@Slf4j
@WebFilter(urlPatterns = "/*")
public class loginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
              // 1,获取url
        String url = req.getRequestURI().toString();
        log.info("请求到的url: {}", url);

        // 2,判断url是否包含'login'
        if (url.contains("login")) {
            log.info("登录操作, 放行...");
            chain.doFilter(request, response);
            return;
        }
        
        // 3, 获取请求头中的token
        String jwt = req.getHeader("token");

        // 4, 判断令牌是否存在
        // 使用springframework提供的工具类
        if (!StringUtils.hasLength(jwt)) {
            log.info("请求头token为空");
            Result error = Result.error("NOT_LOGIN");
            // 手动转换 把 对象-> JSON  ------->使用阿里巴巴fastJSON插件
            String notLogin = JSON.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }
        
        // 5, 解析token
        try {
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            // 解释失败
            log.info("解释令牌失败");
            Result error = Result.error("NOT_LOGIN");
            String notLogin = JSON.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }
             // 6, 放行
        log.info("令牌合法, 放行");
        chain.doFilter(request, response);
    }
}
  1. 在springbott中, 响应的数据会被自动封装为JSON对象
  2. 在过滤器中, 我们要手动把数据转成JSON, 才能响应给前端
// fastjson依赖
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.76</version>
</dependency>

接口测试

拦截器

快速入门

定义拦截器: 实现HandlerIntereptor接口, 并重写其所有方法

@Component
public class LoginCheckInterceptor implements HandlerInterceptor {

    @Override  //目标资源方法运行前运行, 返回true放行,反回false不放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        System.out.println("目标资源方法运行前运行");
        return true;
    }

    @Override //目标资源方法运行后运行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("目标资源方法运行后");
    }

    @Override //视图渲染完毕后运行,最后运行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("视图渲染完毕后");
    }
}
  1. 拦截器的所有方法都有默认实现, 定义拦截器时按需实现接口的方法即可

注册拦截器

@Configuration  //标明配置类
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器,并指定监听路径
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**")
    }
}
详解

配置拦截路径: 拦截器可以根据需求, 配置不同的拦截路径

拦截器的执行流程

过滤器和拦截器的区别

登录校验-Interceptor

使用拦截器完成登录校验, 登录校验的代码的逻辑是不变的, 只是放行方式不同

@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {

    @Override  //目标资源方法运行前运行, 返回true放行,反回false不放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        //1,获取请求URL
        String url = req.getRequestURL().toString();
        log.info("请求的URL:{}", url);

        //2,判断是否包含login,登录操作直接放行
        if (url.contains("login")) {
            log.info("登录操作,放行");
            return true;
        }

        //3,获取请求头的令牌
        String jwt = req.getHeader("token");

        //4,判断令牌是否存在,如果不存在返回错误信息
        if (!StringUtils.hasLength(jwt)) {
            log.info("请求头token信息为空");
            // 创建错误对象
            Result error = Result.error("NOT_LOGIN");
            // 手动转换 对象->JSON
            String notLogin = JSONObject.toJSONString(error);
            // 响应数据
            resp.getWriter().write(notLogin);
            // 阻止代码继续往下执行
            return false;
        }

        //5,解析token,如果解析失败则token无效
        try {
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {
            // 输出错误日志
            e.printStackTrace();
            log.info("解析令牌失败,返回错误信息");
            // 创建错误对象
            Result error = Result.error("NOT_LOGIN");
            // 手动转换 对象->JSON
            String notLogin = JSONObject.toJSONString(error);
            // 响应数据
            resp.getWriter().write(notLogin);
            // 阻止代码继续往下执行
            return false;
        }

        //6,token合法,放行
        log.info("token合法,放行");
        return true;
    }
}
@Configuration  //标明配置类
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器,并指定监听路径,排除监听路径
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2102485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】一文详细向您介绍 bisect_left 函数

【Python】一文详细向您介绍 bisect_left 函数 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本硕&#x…

shell脚本1----编程规范与变量

shell脚本 shell的功能 Shell&#xff08;壳程序&#xff09;是一个特殊的应用程序&#xff0c;它介于操作系统内核与用户之间&#xff0c;充当了一个“命令解释器”的角色&#xff0c;负责接收用户输入的操作指令&#xff08;命令&#xff09;并进行解释&#xff0c;将需要执…

(前端)面试300问之(3)this的指向判断

一、this的相关理解与解读 1、各角度看this。 1&#xff09;ECMAScript规范&#xff1a; this 关键字执行为当前执行环境的 ThisBinding。 2&#xff09;MDN&#xff1a; In most cases, the value of this is determined by how a function is called. 在绝大多数情况下&…

图片损坏,如何修复?

在数字化时代&#xff0c;图片已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;有时我们可能会遇到图片损坏的情况&#xff0c;无论是珍贵的家庭照片、工作文档中的关键图像&#xff0c;还是社交媒体上的分享内容&#xff0c;图片损坏都可能带来不小的困扰。那么…

网络传输加密及openssl使用样例(客户端服务器)

文章目录 背景常用加密方式SSLOpenSSL主要功能 库结构 交互流程证书生成生成 RSA 私钥私钥的主要组成部分私钥的格式 创建自签名证书: 签发证书服务器端代码客户端代码常见错误版本问题证书问题证书格式 背景 网络传输中为保证数据安全&#xff0c;通常需要加密 常用加密方式…

Open3D 基于曲率大小的特征点提取

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 三、实现效果 3.1原始点云 3.2提取特征点 Open3D点云算法汇总及实战案例汇总的目录地址&#xff1a; Open3D点云算法与点云深度学习案例汇总&#xff08;长期更新&#xff09;-CSDN博客 一、概述 基于曲率…

STM32 外部中断(EXTI)

STM32 外部中断(EXTI) 实验&#xff1a;配置一个引脚的下降沿作为外部中断。 参考&#xff1a;江协科技 相关缩写 RCC(Reset and Clock Control) 复位和时钟控制 GPIO(General Purpose Input/Output) 通用输入/输出 AFIO(Alternate Function Input Output) 复用功能输入输…

6.Lab five —— Lazy Page Allocation

首先先切换到lazy分支 git checkout lazy make clean Xv6应用程序使用sbrk()系统调用向内核请求堆内存。sbrk()分配物理内存并将其映射到进程的虚拟地址空间。内核为一个大请求分配和映射内存可能需要很长时间。为了提高效率&#xff0c;故采用懒分配的策略 Eliminate alloc…

Scratch在线玩:3D地铁跑酷

小虎鲸Scratch资源站-免费Scratch作品源码,素材,教程分享平台! 作品介绍&#xff1a; 欢迎体验在 Scratch 上重新制作的 3D 地铁跑酷游戏&#xff01;这款游戏完全采用 3D 技术打造&#xff0c;带来流畅的视觉效果和出色的游戏体验。游戏的目标是避免列车和障碍物&#xff0c;同…

力扣 1419. 数青蛙

力扣 1419. 数青蛙 1. 题目 2. 思路 本题就是一道 字符串模拟题&#xff1b; 题目说到了&#xff0c; 会混杂着青蛙的叫声&#xff0c; 如果字符串 croakOfFrogs 不是由若干有效的 “croak” 字符混合而成&#xff0c;请返回 -1, 那就是说如果有多余的 c, r, o等等, 比如 &quo…

【机器学习】机器学习引领未来:赋能精准高效的图像识别技术革新

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#x1f4d2;2. 机器学习基础与图像识别原理&#x1f341;机器学习概述&#xff1a;监督学习、无监督学习与强化学…

「深入理解」HTML Meta标签:网页元信息的配置

「深入理解」HTML Meta标签&#xff1a;网页元信息的配置 HTML的<meta>元素用于提供关于HTML文档的元数据&#xff08;metadata&#xff09;&#xff0c;这些信息对于浏览器和其他处理HTML文档的应用程序来说是非常有用的&#xff0c;如&#xff1a;<base>、<li…

虚幻引擎VR游戏开发02 | 性能优化设置

常识&#xff1a;VR需要保持至少90 FPS的刷新率&#xff0c;以避免用户体验到延迟或晕眩感。以下是优化性能的一系列设置&#xff08;make sure the frame rate does not drop below a certain threshold&#xff09; In project setting-> &#xff08;以下十个设置都在pr…

用于全栈自动化测试的最佳Python工具

我知道大多数测试人员会说Java是他们创建自动化测试的首选语言。 但是我最喜欢的是Python。为什么?为什么是Python ? Al Sweigart&#xff0c;《自动化那些无聊的东西》的作者&#xff0c;Python一直是他的首选语言&#xff0c;因为:它有一个温和的学习曲线。它适用于Windows…

42.哀家要长脑子了!

1.965. 单值二叉树 - 力扣&#xff08;LeetCode&#xff09; 深度优先搜索&#xff0c;看边两端的结点是不是一样的值 class Solution { public:bool isUnivalTree(TreeNode* root) {if(!root) return true;if(root->right) {if(root->val ! root->right->val || …

数字图像处理基础:图像处理概念、步骤、方式介绍

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…

5.2.数据结构-c/c++二叉树详解(下篇)(算法面试题)

本章所有代码请见&#xff1a;5.3.数据结构-c/c二叉树代码-CSDN博客 上篇:5.数据结构-c/c二叉树详解(上篇)&#xff08;遍历方法&#xff0c;完全二叉树&#xff09;-CSDN博客 目录 1 求二叉树 第k层的节点 2 查找一个节点是否在二叉树中 3 求二叉树节点的个数 4 求二叉树…

c#笔记5 详解事件的内置类型EventHandler、windows事件在winform中的运用

为什么要研究这一问题&#xff1f; 事件和委托可以说是息息相关。 前面先解释了什么是委托&#xff0c;怎么定义一个委托以及怎么使用匿名方法来内联地新建委托。 事实上事件这一机制在c#的程序开发中展很重要的地位&#xff0c;尤其是接触了winform软件开发的同学们应该都知…

chapter12-异常(Exception)——(注解)——day14

444-异常处理入门 445-异常基本介绍 446-异常体系图 虚线代表 实现接口&#xff0c;实线代表继承 447-五大运行时异常 448-异常课堂练习 449-异常处理机制 450-tryCatch异常处理 1&#xff09;如果异常发送&#xff0c;则异常发生后面的代码不会执行&#xff0c;直接进入到Catc…

接口报错403 Forbidden 【已解决】

接口报错403 Forbidden 【已解决】 在Web开发中&#xff0c;接口请求错误是开发者经常遇到的问题之一。其中&#xff0c;403 Forbidden错误尤为常见&#xff0c;它表明服务器理解了客户端的请求&#xff0c;但是拒绝执行此请求。本文将深入探讨接口请求403 Forbidden错误&#…