Servlet 返回“HTTP 状态 404 请求的资源 (/servlet) 不可用”
Posted
技术标签:
【中文标题】Servlet 返回“HTTP 状态 404 请求的资源 (/servlet) 不可用”【英文标题】:Servlet returns "HTTP Status 404 The requested resource (/servlet) is not available" 【发布时间】:2021-05-26 18:48:00 【问题描述】:我的WebContent/jsps
文件夹中的JSP 文件中有一个html 表单。我在src
文件夹的默认包中有一个servlet 类servlet.java
。在我的web.xml
中,它被映射为/servlet
。
我在 HTML 表单的 action
属性中尝试了几个 URL:
<form action="/servlet">
<form action="/servlet.java">
<form action="/src/servlet.java">
<form action="../servlet.java">
但这些都不起作用。他们都在 Tomcat 6/7/8 中不断返回 HTTP 404 错误,如下所示:
HTTP 状态 404 — /servlet
说明:请求的资源(/servlet)不可用。
或在 Tomcat 8.5/9 中如下:
HTTP 状态 404 - 未找到
消息:/servlet
描述:源服务器没有找到目标资源的当前表示或不愿意透露存在的表示
或者在Tomcat 10中如下:
HTTP 状态 404 - 未找到
类型:状态报告
消息:请求的资源(/servlet)不可用
描述:源服务器没有找到目标资源的当前表示或不愿意透露存在的表示
为什么它不起作用?
【问题讨论】:
【参考方案1】:简介
这可能有很多原因,分为以下几节:
将 servlet 类放入package
在url-pattern
中设置servlet URL
@WebServlet
仅适用于 Servlet 3.0 或更高版本
javax.servlet.*
在 Servlet 5.0 或更高版本中不再工作
确保编译后的*.class
文件存在于内置WAR中
在没有任何 JSP/HTML 页面的情况下单独测试 servlet
使用域相对 URL 从 HTML 引用 servlet
在 HTML 属性中使用直引号
将 servlet 类放入 package
首先,将 servlet 类放入 Java package
。您应该始终将可公开重用的 Java 类放入包中,否则它们对于包中的类(例如服务器本身)是不可见的。通过这种方式,您可以消除潜在的特定环境问题。无包 servlet 只能在特定的 Tomcat+JDK 组合中工作,永远不要依赖这一点。
如果是“普通”IDE 项目,则需要将类放在“Java Sources”文件夹内的包结构中,不在“Web Content”文件夹中,该文件夹用于 Web JSP 等文件。下面是在 Navigator 视图中看到的默认 Eclipse Dynamic Web Project 的文件夹结构示例(“Java Sources”文件夹默认位于此类项目中,由 @ 表示987654345@文件夹):
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
如果是 Maven 项目,则需要将类放在 main/java
内的包结构中,因此 不 main/resources
、this is for non-class files 和绝对也不 em> main/webapp
,这是用于网络文件的。下面是在 Eclipse 的 Navigator 视图中看到的默认 Maven webapp 项目的文件夹结构示例:
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
请注意,/jsps
子文件夹并非绝对必要。您甚至可以不使用它并将 JSP 文件直接放在 webcontent/webapp 根目录中,但我只是从您的问题中接手。
在url-pattern
中设置servlet URL
servlet URL 被指定为 servlet 映射的“URL 模式”。绝对不是servlet类的类名/文件名。 URL 模式将被指定为 @WebServlet
注释的值。
package com.example; // Use a package!
@WebServlet("/servlet") // This is the URL of the servlet.
public class YourServlet extends HttpServlet // Must be public and extend HttpServlet.
// ...
如果您想支持/servlet/foo/bar
等路径参数,请改用/servlet/*
的URL 模式。另见Servlet and path parameters like /xyz/value/test, how to map in web.xml?
@WebServlet
仅适用于 Servlet 3.0 或更高版本
为了使用@WebServlet
,您只需要确保您的web.xml
文件(如果有)(自Servlet 3.0 起是可选的)被声明为符合Servlet 3.0+ 版本and thus not conform e.g. 2.5 version or lower。下面是一个 Servlet 4.0 兼容的(匹配 Tomcat 9+、WildFly 11+、Payara 5+ 等)。
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
>
<!-- Config here. -->
</web-app>
或者,如果您还没有使用 Servlet 3.0+(例如 Tomcat 6 或更早版本),请删除 @WebServlet
注释。
package com.example;
public class YourServlet extends HttpServlet
// ...
然后像这样在web.xml
中注册 servlet:
<servlet>
<servlet-name>yourServlet</servlet-name>
<servlet-class>com.example.YourServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>yourServlet</servlet-name>
<url-pattern>/servlet</url-pattern> <!-- This is the URL of the servlet. -->
</servlet-mapping>
因此请注意,您不应同时使用这两种方式。使用基于注释的配置或基于 XML 的配置。如果两者都有,那么基于 XML 的配置将覆盖基于注释的配置。
javax.servlet.*
在 Servlet 5.0 或更高版本中不再工作
自 Jakarta EE 9 / Servlet 5.0(Tomcat 10、TomEE 9、WildFly 22 Preview、GlassFish 6、Payara 6、Liberty 22 等)起,javax.*
包已重命名为 jakarta.*
包。
换句话说,请绝对确保您不会仅仅为了获取javax.*
包而将不同服务器的JAR 文件随机放入您的WAR 项目中,例如tomcat-servlet-api-9.xxjar编译。这只会带来麻烦。完全删除它并编辑您的 servlet 类的导入
import javax.servlet.*;
import javax.servlet.http.*;
到
import jakarta.servlet.*;
import jakarta.servlet.http.*;
如果您使用的是 Maven,您可以在此答案中找到正确的 Tomcat 10+、Tomcat 9-、JEE 9+ 和 JEE 8- 的 pom.xml
声明示例:Tomcat casting servlets to javax.servlet.Servlet instead of jakarta.servlet.http.HttpServlet
确保编译的*.class
文件存在于构建的WAR 中
如果您使用诸如 Eclipse 和/或 Maven 之类的构建工具,那么您需要确保已编译的 servlet 类文件位于生成的 WAR 文件的 /WEB-INF/classes
文件夹中的包结构中。对于package com.example; public class YourServlet
,它必须位于/WEB-INF/classes/com/example/YourServlet.class
。否则您将面临@WebServlet
的情况下也出现404 错误,或者<servlet>
的情况下出现如下HTTP 500 错误:
HTTP 状态 500
实例化 servlet 类 com.example.YourServlet 时出错
并在服务器日志中找到java.lang.ClassNotFoundException: com.example.YourServlet
,然后是java.lang.NoClassDefFoundError: com.example.YourServlet
,然后是javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
。
验证 servlet 是否正确编译并放置在类路径中的一种简单方法是让构建工具生成一个 WAR 文件(例如右键单击项目,Eclipse 中的 Export > WAR 文件)然后检查其内容与 ZIP 工具。如果/WEB-INF/classes
中缺少 servlet 类,或者如果导出导致错误,则项目配置错误或某些 IDE/项目配置默认值被错误恢复(例如 Project > Build Automatically在 Eclipse 中被禁用)。
您还需要确保项目图标没有表示构建错误的红叉。您可以在 Problems 视图中找到确切的错误(Window > Show View > Other...)。通常错误消息很好谷歌搜索。如果您不知道,最好从头开始,不要触及任何 IDE/项目配置默认值。如果您使用的是 Eclipse,您可以在 How do I import the javax.servlet / jakarta.servlet API in my Eclipse project? 中找到说明
在没有任何 JSP/HTML 页面的情况下单独测试 servlet
假设服务器在localhost:8080
上运行,并且WAR 成功部署在/contextname
的上下文路径上(默认为IDE 项目名称,区分大小写!),并且servlet 没有失败初始化(读取任何部署/servlet 成功/失败消息的服务器日志以及实际上下文路径和 servlet 映射),然后在http://localhost:8080/contextname/servlet
处提供具有/servlet
的 URL 模式的 servlet。
您可以直接在浏览器的地址栏中输入它来单独测试它。如果它的doGet()
被正确覆盖和实现,那么您将在浏览器中看到它的输出。或者,如果您没有任何doGet()
,或者如果它错误地调用super.doGet()
,则会显示“HTTP 405: HTTP method GET is not supported by this URL”错误(这仍然比 404 好,因为 405 证明 servlet 本身实际上是找到)。
重写 service()
是一种不好的做法,除非您正在重新发明 MVC 框架 — 如果您刚开始使用 servlet 并且对当前问题中描述的问题一无所知,这不太可能;) 另请参阅Design Patterns web based applications.
无论如何,如果 servlet 在单独测试时已经返回 404,那么尝试使用 HTML 表单是完全没有意义的。因此,从逻辑上讲,在有关 servlet 的 404 错误的问题中包含任何 HTML 表单也是完全没有意义的。
使用域相对 URL 从 HTML 引用 servlet
一旦您确认 servlet 在单独调用时工作正常,您就可以前进到 HTML。至于 HTML 表单的具体问题,<form action>
值必须是有效的 URL。这同样适用于<a href>
、<img src>
、<script src>
等。您需要了解绝对/相对 URL 的工作原理。您知道,URL 是一个网址,您可以在网络浏览器的地址栏中输入/查看。如果您将相对 URL 指定为表单操作,即没有 http://
方案,那么它会变成相对于 当前 URL,如您在 Web 浏览器的地址栏中看到的那样。因此,它与许多初学者似乎认为的服务器的 WAR 文件夹结构中的 JSP/HTML 文件位置绝对无关。
因此,假设带有 HTML 表单的 JSP 页面由 http://localhost:8080/contextname/jsps/page.jsp
打开(因此 不是 由 file://...
打开),您需要提交到位于 http://localhost:8080/contextname/servlet
的 servlet ,这里有几种情况(请注意,您可以在这里安全地将<form action>
替换为<a href>
、<img src>
、<script src>
等):
表单操作提交到带有前导斜杠的 URL。
<form action="/servlet">
前导斜杠/
使URL 相对于域,因此表单将提交到
http://localhost:8080/servlet
但这可能会导致 404,因为它在错误的上下文中。
表单操作提交到不带前导斜杠的 URL。
<form action="servlet">
这使得 URL 相对于当前 URL 的当前文件夹,因此表单将提交到
http://localhost:8080/contextname/jsps/servlet
但这可能会导致 404,因为它位于错误的文件夹中。
表单操作提交到一个向上一个文件夹的 URL。
<form action="../servlet">
这将向上一个文件夹(就像在本地磁盘文件系统路径中一样!),因此表单将提交到
http://localhost:8080/contextname/servlet
这个一定行得通!
然而,规范的方法是使 URL 与域相关,这样当您碰巧将 JSP 文件移动到另一个文件夹中时,您不需要再次修复 URL。
<form action="$pageContext.request.contextPath/servlet">
这会生成
<form action="/contextname/servlet">
因此将始终提交到正确的 URL。
在 HTML 属性中使用直引号
您需要确保在 HTML 属性中使用直引号,例如 action="..."
或 action='...'
,因此 不要 使用大引号,例如 action=”...”
或 action=’...’
。 HTML 不支持弯引号,它们只会成为值的一部分。从博客复制粘贴代码 sn-ps 时要小心!一些博客引擎,特别是 Wordpress,默认使用所谓的“智能引号”,因此也会以这种方式破坏代码 sn-ps 中的引号。另一方面,不要复制粘贴代码,而是尝试自己简单地输入代码。通过大脑和手指实际获取代码的另一个好处是,它可以让您长期更好地记住和理解代码,同时让您成为更好的开发人员。
另见:
Our servlets wiki page - 包含一些 hello world 示例 How to call servlet class from HTML form doGet and doPost in Servlets How do I pass current item to Java method by clicking a hyperlink or button in JSP page?其他HTTP状态404错误情况:
HTTP Status 404 - Servlet [ServletName] is not available HTTP Status 404 - The requested resource (/ProjectName/) is not available HTTP Status 404 - The requested resource (/) is not available JSP in /WEB-INF returns "HTTP Status 404 The requested resource is not available" Referencing a resource placed in WEB-INF folder in JSP file returns HTTP 404 on resource Browser can't access/find relative resources like CSS, images and links when calling a Servlet which forwards to a JSP【讨论】:
web-app version="3.1" 使用 glassfish,当我在 web.xml 中有一个映射和注释时,我可以单独测试我的 servlet。我删除了映射并留下了注释,因为我有最新版本,但是我会收到 404 错误? 如果您在 webapp 本身中包含 servlet 2.5 或更旧的库,而不是依赖目标运行时自行提供 servlet 库,就会发生这种情况。【参考方案2】:场景#1:您在tomcat已经在运行时意外地从命令行重新部署。
简答:停止Tomcat,删除目标文件夹,mvn包,然后重新部署
场景 #2: request.getRequestDispatcher("MIS_SPELLED_FILE_NAME.jsp")
简答:检查文件名拼写,确保大小写正确。
场景 #3:找不到类异常 (答案放在这里,因为:问题#17982240) (java.lang.ClassNotFoundException for servlet in tomcat with eclipse) (被标记为重复并在此处指示我)
简答 #3.1:web.xml 在 servlet-class 标签中有错误的包路径。
简答 #3.2:java 文件有错误的导入语句。
以下是场景 #1 的更多详细信息:
1:停止Tomcat
选项 1:通过终端中的 CTRL+C。 选项 2:(终端在 Tomcat 仍在运行时关闭) ------------ 2.1:按:Windows+R --> 输入:“services.msc” ------------ 2.2:在列表的名称列中找到“Apache Tomcat #.# Tomcat#”。 ------------ 2.3: 右键 --> "stop"2:删除“目标”文件夹。 (这里 mvn clean 帮不了你)
3: mvn 包
4:YOUR_DEPLOYMENT_COMMAND_HERE
(我的:java -jar target/dependency/webapp-runner.jar --port 5190 target/*.war)
完整的背景故事:
不小心打开了一个新的 git-bash 窗口,然后 尝试通过以下方式为我的 heroku 项目部署 .war 文件:
java -jar target/dependency/webapp-runner.jar --port 5190 target/*.war
部署失败后,我意识到我打开了两个 git-bash 窗口, 并且没有使用 CTLR+C 停止之前的部署。
我遇到了:
HTTP 状态 404 - 未找到类型状态报告
留言/if-student-test.jsp
描述 源服务器没有找到当前的表示 对于目标资源或不愿透露该资源 存在。
Apache Tomcat/8.5.31
以下是场景 #3 的更多详细信息:
场景 3.1: servlet 类包路径错误 在您的 web.xml 文件中。
它应该匹配顶部的包语句 你的 java servlet 类。
文件:my_stuff/MyClass.java:
package my_stuff;
文件:PRJ_ROOT/src/main/webapp/WEB-INF/web.xml
<servlet-class>
my_stuff.MyClass
</servlet-class>
场景 3.2:
你放错了“package”语句 在 myClass.java 文件的顶部。
例如:
文件位于:“/my_stuff”文件夹中
你写错了:
package com.my_stuff
这很棘手,因为:
1:maven build(mvn包)这里不会报错。
2:web.xml 中的 servlet-class 行可以有正确的包路径。例如:
<servlet-class>
my_stuff.MyClass
</servlet-class>
使用的堆栈: Notepad++ + GitBash + Maven + Heroku Web App Runner + Tomcat9 + Windows10:
【讨论】:
您的 AppName.war,因此展开的文件夹名称与您的预期名称不匹配,例如,当您的 war 文件版本控制为 AppName-1.0-SNAPSHOT.war 并且您正在尝试 /AppName/ .【参考方案3】:检查您是否输入了 Web.xml 中指定的正确 URL 映射
例如:
在 web.xml 中,您的 servlet 声明可能是:
<servlet>
<servlet-name>ControllerA</servlet-name>
<servlet-class>PackageName.ControllerA</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ControllerA</servlet-name>
<url-pattern>/theController</url-pattern>
</servlet-mapping>
这个sn-p 所做的是<url-pattern>/theController</url-pattern>
将设置用于从前端通过URL 调用servlet 的名称(例如:表单)。所以当你在前端引用servlet时,为了保证请求到达servlet“ControllerA”,它应该从表单中引用指定的URL Pattern“theController”。
例如:
<form action="theController" method="POST">
</form>
【讨论】:
【参考方案4】:NetBeans IDE 中HTTP Status 404
的解决方案:
右键单击您的项目并转到您的项目属性,然后单击运行,然后输入您的项目相对 URL,例如 index.jsp
。
-
项目->属性
点击运行
相对 URL:/index.jsp(选择您的项目根 URL)
【讨论】:
【参考方案5】:我的问题是我的方法缺少 @RequestBody 注释。添加注释后,我不再收到 404 异常。
【讨论】:
【参考方案6】:执行以下两个步骤。希望能解决java servlet应用开发过程中tomcat服务器“404 not found”的问题。
第一步:Right click on the server(in the server explorer tab)->Properties->Switch Location from workspace metadata to tomcat server
第二步:Double Click on the server(in the server explorer tab)->Select Use tomcat installation option inside server location menu
【讨论】:
【参考方案7】:我删除了旧的 web 库,例如 spring 框架库。并建立图书馆的新路径。然后就可以了。
【讨论】:
【参考方案8】:一个旧线程,但由于我没有在其他地方找到它,这里还有一种可能性:
如果您使用的是 servlet-api 3.0+,那么您的 web.xml 必须不包含 metadata-complete="true"
属性
这告诉 tomcat 使用 web.xml
中给出的数据而不是使用 @WebServlet
注释来映射 servlet。
【讨论】:
【参考方案9】:首先,以管理员身份运行您的 IDE。之后,右键单击项目文件夹 -> Project Facets 并确保 Java 版本设置正确。在我的电脑上。 (例如 1.8)现在它应该可以工作了。
不要只使用 cmd 启动服务器,例如 Wildfly。它必须在 IDE 中启动,现在访问您的 localhost URL。示例:http://localhost:8080/HelloWorldServlet/HelloWorld
【讨论】:
【参考方案10】:对我有用的修复是(如果您使用的是 Maven):右键单击您的项目,Maven -> 更新项目。这可能会给 JDK 和其他库(在我的例子中是 mysql 连接器)带来一些其他错误,但是一旦您修复它们,您的原始问题应该得到修复!
【讨论】:
【参考方案11】:如果您想在不使用“表单”和“提交”按钮的情况下使用 javascript 打开 servlet,请使用以下代码:
var button = document.getElementById("<<button-id>>");
button.addEventListener("click", function()
window.location.href= "<<full-servlet-path>>" (eg. http://localhost:8086/xyz/servlet)
);
键:
1) button-id : 您在 html/jsp 文件中为按钮指定的“id”标签。
2) full-servlet-path:单独运行servlet时在浏览器中显示的路径
【讨论】:
【参考方案12】:web.xml 中的映射是我所做的:-
-
如果为新程序制作了另一个包,那么我们必须提及:-
xml 文件中 servlet-class 标记的打开和关闭之间的 packagename.filename。
-
如果您在 xml 中映射文件并且它们无法正常工作或显示错误,请在相应文件中的代码注释行中添加注释。
这两种方法不能相互配合,所以要么我使用创建servlet时提到的文件的注释方法或映射方式,然后我删除或注释注释行。例如:
<servlet>
<servlet-name>s1</servlet-name>
<servlet-class>performance.FirstServ</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s1</servlet-name>
<url-pattern>/FirstServ</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>s2</servlet-name>
<servlet-class>performance.SecondServ</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s2</servlet-name>
<url-pattern>/SecondServ</url-pattern>
</servlet-mapping>
如果在 xml 中映射完成,请在相应文件中注释代码行。
//@WebServlet("/FirstServ")
//@WebServlet("/SecondServ")
【讨论】:
【参考方案13】:如果有人在这里使用 MySQL,并且感觉代码在前一天可以正常工作,而现在却不行,那么我想你必须打开 MySQL CLI 或 MySQL Workbench,然后只连接一次数据库。连接后,数据库也会连接到 Java 应用程序。我曾经收到 Hibernate Dialect 错误,说明 com.mysql.jdbc.Driver 有问题。我认为某些计算机中的 MySQL 存在启动问题。这为我解决了。
【讨论】:
【参考方案14】:如果您是一名学生并且刚接触 Java,那么您的 web.xml 文件可能会出现一些问题。
尝试删除 web.xml 文件。 其次检查您的路径变量是否设置正确。 重启 tomcat 服务器或你的电脑。
你的问题一定会解决的。
【讨论】:
【参考方案15】:我也遇到了这个问题,在访问我知道链接到 Servlet 的 URL 模式时收到 404。原因是我有 2 个 Servlet,它们的 @WebServlet name
参数设置为相同的字符串。
@WebServlet(name = "ServletName", urlPatterns = "/path")
public class ServletName extends HttpServlet
@WebServlet(name = "ServletName", urlPatterns = "/other-path")
public class OtherServletName extends HttpServlet
name
的两个参数是相同的。如果您使用 name 参数,请确保它们与您应用程序中的所有其他 Servlet 相比是唯一的。
【讨论】:
【参考方案16】:我遇到了同样的问题。尝试了所有这些但没有帮助。我设法通过在 xml 文件的开头和结尾添加元素标签来解决这个问题。生病将我的 xml 文件留在下面以供参考。
<?xml version="1.0" encoding="UTF-8"?>
<element>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>InsertServlet</servlet-name>
<servlet-class>com.worklog.InsertServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>InsertServlet</servlet-name>
<url-pattern>/insert</url-pattern>
</servlet-mapping>
</web-app>
</element>
【讨论】:
【参考方案17】:如果您使用的是 IntelliJ,这就是为我解决的问题:
进入 Tomcat 配置:
配置 > 部署选项卡
向下滚动并将/
添加到应用程序上下文下拉列表中
【讨论】:
【参考方案18】:我遇到了同样的问题。我正在开发一个基于 mvc 的 REST API,其中没有明确的 html 配置或文件。 API 使用 Swagger 生成用户界面。当我介绍 Swagger 版本“3.0.0”时,问题就开始了。我恢复到 Swagger "2.9.2" 这解决了我的问题。
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
【讨论】:
【参考方案19】:请检查上下文根不能为空。
如果您使用的是 eclipse:右键单击,选择属性,然后选择Web 项目设置。检查上下文根不能为空
【讨论】:
以上是关于Servlet 返回“HTTP 状态 404 请求的资源 (/servlet) 不可用”的主要内容,如果未能解决你的问题,请参考以下文章
Servlet 返回“HTTP 状态 404 请求的资源 (/servlet) 不可用”
Servlet 返回“HTTP 状态 404 请求的资源 (/servlet) 不可用”
Servlet 返回“HTTP 状态 404 请求的资源 (/servlet) 不可用”
Servlet 返回“HTTP 状态 404 请求的资源 (/servlet) 不可用”