Spring Boot项目的404是如何发生的
问题
在日常开发中,假如我们访问一个Sping容器中并不存在的路径,通常会返回404的报错,具体原因是什么呢?
结论
错误的访问会调用两次DispatcherServlet:第一次调用无法找到对应路径时,会给Response设置一个错误状态,第二次是根据这个状态执行预先设置了error属性的DispatcherServlet。而正确的访问只会调用一次DispatcherServlet。
原理
我们知道,基于SpringMvc原理的Spring Boot项目,所有的路由请求默认都是由DispatcherServlet类来负责处理的?
如果开启断点调试会发现在第二次进入DispatcherServlet的doDispatch方法时,便直接返回了404错误:
那么问题的重点应该出现在两次DispatcherServlet的调用上,通过调试可以发现,最后一次的调用分析的意义不大,因为从它的request属性就能看出来,它预先设置了一堆的错误属性,明显就是为了返回错误,走了一遍DispatcherServlet的标准流程。
重点只有两点:
第一次执行DispatcherServlet的过程中发生了什么?
错误的请求为什么会有两次DispatcherServlet调用?
1.1 第一次执行DispatcherServlet
通过断点调试,可以看到在执行DispatcherServlet中的doDispatch方法的时候进入了HttpRequestHandlerAdapter的handle方法
public class HttpRequestHandlerAdapter implements HandlerAdapter {public HttpRequestHandlerAdapter() {}public boolean supports(Object handler) {return handler instanceof HttpRequestHandler;}@Nullablepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {((HttpRequestHandler)handler).handleRequest(request, response);return null;}
......
接着又执行了ResourceHttpRequestHandler的handleRequest方法,在执行的过程中,在容器中没有找到对应的路径,所以对response设置了404错误:
也就是
response.sendError(404)
它的底层实际上是给Response类的一个私有属性errorState,设置了错误状态:
public boolean setError() {return this.errorState.compareAndSet(0, 1);}
这样设置有什么用呢?
这就涉及到第二次执行DispatcherServlet的原因了。
1.2 错误请求为什么会执行两次DispatcherServlet
重点在StandardHostValve类的invoke方法中:
public final void invoke(Request request, Response response) throws IOException, ServletException {......try {//第一次执行DispatcherServlet的原因if (!response.isErrorReportRequired()) {//执行正常的请求context.getPipeline().getFirst().invoke(request, response);}} catch (Throwable var10) {ExceptionUtils.handleThrowable(var10);this.container.getLogger().error("Exception Processing " + request.getRequestURI(), var10);if (!response.isErrorReportRequired()) {request.setAttribute("javax.servlet.error.exception", var10);this.throwable(request, response, var10);}}response.setSuspended(false);Throwable t = (Throwable)request.getAttribute("javax.servlet.error.exception");if (context.getState().isAvailable()) {//第二次执行DispatcherServlet的原因if (response.isErrorReportRequired()) {AtomicBoolean result = new AtomicBoolean(false);response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);if (result.get()) {if (t != null) {this.throwable(request, response, t);} else {//执行错误请求this.status(request, response);}}}......
两次执行的原因是因为
response.isErrorReportRequired()
public class Response implements HttpServletResponse {
public boolean isErrorReportRequired() {return this.getCoyoteResponse().isErrorReportRequired();}
......public final class Response {public boolean isErrorReportRequired() {return this.errorState.get() == 1;
}
.....
也就是根据Response类的私有属性errorState来判断的。
第一次执行DispatcherServlet的时候,由于errorState的值还是初始化值0,所以可以正常执行,执行的时候找不到对应的路径资源,便执行了response.sendError(404)方法,给errorState赋值为1。
这是StandardHostValve类中,invoke执行的
context.getPipeline().getFirst().invoke(request, response);
给errorState赋值1以后,又执行了:
this.status(request, response);
它的执行链路是这样:
status -> custom -> forward -> doForward -> processRequest ->doFilter。
也就是对本次请求执行了一次转发,最后重新调用了一遍
filterChain.doFilter(request, response)
的流程,走了错误调用。
在processRequest方法可以比较看的比较明确:
private void processRequest(ServletRequest request, ServletResponse response, State state) throws IOException, ServletException {DispatcherType disInt = (DispatcherType)request.getAttribute("org.apache.catalina.core.DISPATCHER_TYPE");if (disInt != null) {boolean doInvoke = true;if (this.context.getFireRequestListenersOnForwards() && !this.context.fireRequestInitEvent(request)) {doInvoke = false;}if (doInvoke) {if (disInt != DispatcherType.ERROR) {state.outerRequest.setAttribute("org.apache.catalina.core.DISPATCHER_REQUEST_PATH", this.getCombinedPath());state.outerRequest.setAttribute("org.apache.catalina.core.DISPATCHER_TYPE", DispatcherType.FORWARD);this.invoke(state.outerRequest, response, state);} else {this.invoke(state.outerRequest, response, state);}if (this.context.getFireRequestListenersOnForwards()) {this.context.fireRequestDestroyEvent(request);
......
等到DispatcherServlet再执行完一次,便能在浏览器看到404报错了。
相关文章:
![](https://i-blog.csdnimg.cn/direct/fdf0340a7d4c492fb60e7fe7cef19856.png)
Spring Boot项目的404是如何发生的
问题 在日常开发中,假如我们访问一个Sping容器中并不存在的路径,通常会返回404的报错,具体原因是什么呢? 结论 错误的访问会调用两次DispatcherServlet:第一次调用无法找到对应路径时,会给Response设置一个…...
![](https://i-blog.csdnimg.cn/direct/e0b46a7b4ea047d09b3d695588c19deb.png)
<数据集>手势识别数据集<目标检测>
数据集格式:VOCYOLO格式 图片数量:2400张 标注数量(xml文件个数):2400 标注数量(txt文件个数):2400 标注类别数:5 标注类别名称:[fist, no_gesture, like, ok, palm] 序号类别名称图片数框数1fist597…...
![](https://www.ngui.cc/images/no-images.jpg)
【Vue3】选项式 API
【Vue3】选项式 API 背景简介开发环境开发步骤及源码总结 背景 随着年龄的增长,很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来,技术出身的人总是很难放下一些执念,遂将这些知识整理成文,以纪念曾经努力学习奋斗的日子。…...
![](https://i-blog.csdnimg.cn/direct/1c7084242c4e4752aaea021dbafe291e.png)
2、如何发行自己的数字代币(truffle智能合约项目实战)
2、如何发行自己的数字代币(truffle智能合约项目实战) 1-Atom IDE插件安装2-truffle tutorialtoken3-tutorialtoken源码框架分析4-安装openzeppelin代币框架(代币发布成功) 1-Atom IDE插件安装 正式介绍基于web的智能合约开发 推…...
![](https://i-blog.csdnimg.cn/direct/599fdcfb46d94a92b112e6e41457d439.png)
百日筑基第二十三天-23种设计模式-创建型总汇
百日筑基第二十三天-23种设计模式-创建型总汇 前言 设计模式可以说是对于七大设计原则的实现。 总体来说设计模式分为三大类: 创建型模式,共五种:单例模式、简单工厂模式、抽象工厂模式、建造者模式、原型模式。结构型模式,共…...
![](https://i-blog.csdnimg.cn/direct/bf31b0300a874feeb30129eb1fd1c57f.png)
张量的基本使用
目录 1.张量的定义 2.张量的分类 3.张量的创建 3.1 根据已有数据创建张量 3.2 根据形状创建张量 3.3 创建指定类型的张量 1.张量的定义 张量(Tensor)是机器学习的基本构建模块,是以数字方式表示数据的形式。PyTorch就是将数据封装成张量…...
![](https://www.ngui.cc/images/no-images.jpg)
Oracle(14)什么是唯一键(Unique Key)?
唯一键(Unique Key)是数据库表中的一个或多个列,它们的值必须在整个表中唯一,但允许包含NULL值。唯一键的主要目的是确保表中每一行的数据在指定的列(或列组合)中是唯一的,以防止重复数据的出现…...
![](https://i-blog.csdnimg.cn/direct/9e1ee3b663c24030b8c480c4107ebf20.png)
PostgreSQL的引号、数据类型转换和数据类型
一、单引号和双引号(重要): 1、在mysql没啥区别 2、在pgsql中,实际字符串用单引号,双引号相当于mysql的,用来包含关键字; -- 单引号,表示user_name的字符串实际值 insert into t_user(user_nam…...
![](https://www.ngui.cc/images/no-images.jpg)
Mad MAD Sum-Codeforces Round 960 (Div. 2)
题目在这里 大意: MAD函数返回出现次数 ≥ 2 \geq2 ≥2的最大整数 b i b_i bi M A D ( a [ 1 , 2 , . . . i ] ) MAD(a[1,2,...i]) MAD(a[1,2,...i]) 每次操作把 a i a_i ai进行上述操作,直到全变为0为止,对每次操作的数组进行求和,记…...
![](https://www.ngui.cc/images/no-images.jpg)
Flutter 插件之 package_info_plus
当使用Flutter开发应用时,通常需要获取应用程序的基本信息,例如包名、版本号和构建号。Flutter提供了一个名为 package_info_plus 的插件,它能方便地帮助我们获取这些信息。 1. 添加依赖 首先,需要在项目的 pubspec.yaml 文件中添加 package_info_plus 的依赖。打开 pubs…...
![](https://img-blog.csdnimg.cn/img_convert/e93cfce3acd4b42e3fe6f961dbb9ef7b.png)
如何实现布隆过滤器?
1.布隆过滤器的场景 在Redis 缓存击穿(失效)、缓存穿透、缓存雪崩怎么解决?中我们说到可以使用布隆过滤器避免「缓存穿透」。 你会说我们只要记录了每个用户看过的历史记录,每次推荐的时候去查询数据库过滤存在的数据实现去重。 …...
![](https://i-blog.csdnimg.cn/direct/93e858fcf8a34a5ba057e70ca1d95a4e.png)
运维团队如何高效监控容器化环境中的PID及其他关键指标
随着云计算和容器化技术的快速发展,越来越多的企业开始采用容器化技术来部署和管理应用程序。然而,容器化环境的复杂性和动态性给运维团队带来了前所未有的挑战。本文将从PID(进程标识符)监控入手,探讨运维团队如何高效…...
![](https://i-blog.csdnimg.cn/direct/c980f93a41f74508a887da0ebb851d65.gif)
通过vue3 + TypeScript + uniapp + uni-ui 实现下拉刷新和加载更多的功能
效果图: 核心代码: <script lang="ts" setup>import { ref, reactive } from vue;import api from @/request/api.jsimport empty from @/component/empty.vueimport { onLoad,onShow, onPullDownRefresh, onReachBottom } from @dcloudio/uni-applet form …...
![](https://i-blog.csdnimg.cn/direct/43a7fcd67ead42b5ae7d46a6d8bc29d3.png)
Pointnet++改进即插即用系列:全网首发WTConv2d大接受域的小波卷积|即插即用,提升特征提取模块性能
简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入WTConv2d,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二 2.3 步骤三 1.理…...
![](https://img-blog.csdnimg.cn/img_convert/9da42a68b4723c4be3305f983dfb2635.jpeg)
4核16G服务器支持多少人?4C16G服务器性能测评
租赁4核16G服务器费用,目前4核16G服务器10M带宽配置70元1个月、210元3个月,那么能如何呢?配置为ECS经济型e实例4核16G、按固定带宽10Mbs、100GB ESSD Entry系统盘。 那么问题来了,4C16G10M带宽的云服务器可以支持多少人同时在线&…...
![](https://i-blog.csdnimg.cn/direct/8489879b94f8486185e8492b035e2c9d.png)
塔子哥的平均数-美团2023笔试(codefun2000)
题目链接 塔子哥的平均数-美团2023笔试(codefun2000) 题目内容 给定一个正整数数组a1 ,a2 ,…,an,求平均数正好等于k的最长连续子数组的长度 输入描述 输出描述 输出一个整数,表示最长满足题目条件的长度。 样例1 输入 5 2 1 3 2 4 1 输出 3 样例1解释…...
![](https://i-blog.csdnimg.cn/direct/40ef964d45b34b7fb1ded718e58e7608.jpeg)
故障诊断 | 基于小波包能量谱对滚动轴承的故障诊断Matlab代码
故障诊断 | 基于小波包能量谱对滚动轴承的故障诊断Matlab代码 目录 故障诊断 | 基于小波包能量谱对滚动轴承的故障诊断Matlab代码效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于小波包能量谱对滚动轴承的故障诊断 matlab代码 数据采用的是凯斯西储大学数据 首先利用…...
![](https://i-blog.csdnimg.cn/direct/941785a86e5a4e51bed62ce0f88e225b.png)
E14.【C语言】练习:有关短路运算
#include <stdio.h> int main() {int i 0,a0,b2,c 3,d4;i a && b && d;printf("a %d\nb %d\nc %d\nd %d\n", a, b, c, d);return 0; } 求输出结果 分析: a:先使用后 ,a(见第15篇http://…...
![](https://i-blog.csdnimg.cn/direct/31dce92eb79a4c76b3ddaa8ed73f5ef0.png#pic_center)
python BeautifulSoup库安装与使用(anaconda、pip)
BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库。Beautiful Soup 已成为和 lxml、html5lib 一样出色的Python解释器,为用户灵活地提供不同的解析策略或强劲的速度。 Requests 获取html BeautifulSoup 解析html、xml,BeautifulSoup4库也称bs4库 安装B…...
![](https://i-blog.csdnimg.cn/direct/081c0d72636a49a2905c8007d217bc88.png)
基于Matlab的数据可视化
基于Matlab的数据可视化 一、二维图形的绘制(一)基本图形函数(1)plot函数(2)fplot函数(3)其他坐标系的二维曲线 (二)图形属性设置(1)线…...
![](https://i-blog.csdnimg.cn/direct/4f1b9411f88f4a60a1f1128dedf91467.png)
深入理解Linux网络(二):UDP接收内核探究
深入理解Linux网络(二):UDP接收内核探究 一、UDP 协议处理二、recvfrom 系统调⽤实现 一、UDP 协议处理 udp 协议的处理函数是 udp_rcv。 //file: net/ipv4/udp.c int udp_rcv(struct sk_buff *skb) {return __udp4_lib_rcv(skb, &udp_…...
![](https://i-blog.csdnimg.cn/direct/ab254848835641688698a04e0f4a0b58.png#pic_center)
linux内核中list的基本用法
内核链表 1 list_head 结构 为了使用链表机制,驱动程序需要包含<linux/types.h>头文件,该文件定义了如下结构体实现双向链: struct list_head {struct list_head *next, *prev; };2 链表的初始化 2.1 链表宏定义和初始化 可使用以…...
![](https://www.ngui.cc/images/no-images.jpg)
项目中无关痛痒的词句背后深层含义
项目中听上去无关痛痒的词句背后,深层含义有的时候并不友善。 他们说的:进度表有些激进 真正的意思:我们有麻烦了 他们说的:我们将在接下来的几个迭代里面弥补延误 真正的意思:我们还是有麻烦 他们说的࿱…...
![](https://www.ngui.cc/images/no-images.jpg)
DLMS协议中的高级安全(HLS)身份验证
1.四步身份验证协议 在IEC 62056-53中已说明,ACSE提供部分高级身份安全(HLS)验证服务。高级身份安全验证适用于通信通道不能提供内部安全,应采取防范措施以防止偷听和信息(密码)重现的情况。这时ÿ…...
![](https://www.ngui.cc/images/no-images.jpg)
2024“钉耙编程”杭电多校1006 序列立方(思维+前缀和优化dp)
来源 题目 Problem Description 给定长度为 N 的序列 a。 一个序列有很多个子序列,每个子序列在序列中出现了若干次。 小马想请你输出序列 a 每个非空子序列出现次数的立方值的和,答案对 998244353 取模。 你可以通过样例解释来辅助理解题意。 Input 第…...
![](https://img-blog.csdnimg.cn/img_convert/d3ee64ab0df02bcca2967c4fa03a40a5.png)
钡铼分布式I/O系统边缘计算Modbus,MQTT,OPC UA耦合器BL206
BL206系列耦合器是一个数据采集和控制系统,基于强大的32 位微处理器设计,采用Linux操作系统,支持Modbus,MQTT,OPC UA协议,可以快速接入现场PLC、DCS、PAS、MES、Ignition和SCADA以及ERP系统,同时…...
![](https://i-blog.csdnimg.cn/direct/9726843f78554b8bb6d12619298e2dac.png)
防火墙--双机热备
目录 双击热备作用 防火墙和路由器备份不同之处 如何连线 双机 热备 冷备 VRRP VGMP(华为私有协议) 场景解释 VGMP作用过程 主备的形成场景 接口故障的切换场景 整机故障 原主设备故障恢复的场景 如果没有开启抢占 如果开启了抢占 负载分…...
![](https://www.ngui.cc/images/no-images.jpg)
机器学习 -逻辑回归的似然函数
公式解释 公式如下: L ( θ ) ∏ i 1 m P ( y i ∣ x i ; θ ) ∏ i 1 m ( h θ ( x i ) ) y i ( 1 − h θ ( x i ) ) 1 − y i L(\theta) \prod_{i1}^m P(y_i | x_i; \theta) \prod_{i1}^m (h_\theta(x_i))^{y_i} (1 - h_\theta(x_i))^{1 - y_i} L(θ)i1∏…...
![](https://i-blog.csdnimg.cn/direct/3ac3ba5911e5401094669a9415b447ad.png)
go 实现websocket以及详细设计流程过程,确保通俗易懂
websocket简介: WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。WebSocket 协议在 2011 年由 IETF 标准化为 RFC 6455,后由 RFC 7936 补充规范。 WebSocket 使得客户端和服务器之间的数…...
![](https://www.ngui.cc/images/no-images.jpg)
记录工作中遇到的关于更新丢失商品超开的一个坑
场景: 工作中使用MybatisPlus以及Oracle进行数据库操作,收到RocketMQ消息开始并发分摊不同清货单的商品的批次,并对商品更新冻结数量。 上线后频繁出现商品超库存开票问题。(还好是内部业务,人工替换批次记账即可&…...
![](https://imgsa.baidu.com/exp/w=500/sign=46c550d5f91f4134e037057e151e95c1/80cb39dbb6fd526630cdf122af18972bd4073626.jpg)
定远建设局网站/关键词优化排名的步骤
浏览器记住密码,怎么查看密码是什么? 听语音| 浏览:7891 | 更新:2015-01-28 14:26 | 标签:浏览器 1234567分步阅读现在浏览器都有一种功能叫记住密码,其实这样很不安全。 你眼睛看的那几个‘******’并没有…...
做视频网站 视频放在哪/现在做推广的新渠道有哪些
在这里输入你的内容,注意不要用退格键把所有文字删除,请保留一个或者用鼠标选取后直接输入,防止格式错乱。 没有所谓的成功学,只有充满智慧的思考,脚踏实地的实干,和越来越近的理想,还有机遇和运…...
![](https://images0.cnblogs.com/blog/231772/201304/24162749-8c032923a1574439a6b29d624695e0b0.png)
wordpress如何恢复默认主题/如何建立和设计公司网站
在ios程序间通信,可以通过URL Scheme,判断是否安装了另外的应用,打开特定 URL 的方式来传递参数给 另一个程序。例如:在程序A(Receiver)的Info.plist中加入你需要注册的URL Scheme,然后在你的应…...
![](https://img-blog.csdnimg.cn/20210319161253830.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNDE4MTY5,size_16,color_FFFFFF,t_70)
做联盟 网站 跳转 防止垃圾外链/青岛seo推广公司
如何画前趋图?看了这篇秒懂!(OS前趋图画法) 题目1 画出下面4条语句的前趋图(符号“:”是赋值的意思) S1:a:xy S2:b:z1 S3:c:a-b S4&a…...
![](/images/no-images.jpg)
如果做游戏的技术用来做网站/国内推广平台有哪些
这里写的是关于FOXMAIL点“发送”按钮无反应的问题,这是因为FOXMAIL邮箱文件夹有2G的容量限制导致。解决办法如下: 一个文件箱中的单个文件达到2G的时候也就爆了,网络上有很多的教程来处理2G容量的限制,其实很简单的,没…...
![](/images/no-images.jpg)
网站建设与管理试题及答案/营销软文300字
j2me : 我 new TextField("Id: " , "" , 30 , TextField.NUMERIC) ; 但是当我提交form的时候始终无法提交完成,也就是成功后的页面跳转,最后才发现,当我输入数字长度超过 10 , form就无法提交&…...