Servlet 返回“ HTTP Status 404请求的资源(/Servlet)不可用”

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">

但是这些都不起作用,它们都不断返回 HTTP 404错误,如 Tomcat 6/7/8中所示:

HTTP 状态404ーー/servlet

说明 : 请求的资源(/servlet)不可用。

或者如下面的 Tomcat 8.5/9:

HTTP Status 404 — Not Found

消息 :/servlet

Description : 原始服务器没有找到目标资源的当前表示形式,或者不愿意披露目标资源的存在

或者如下面的 Tomcat 10所示:

HTTP 状态404-未找到

类型 : 状态报告

消息 : 请求的资源(/servlet)不可用

Description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists

为什么不起作用?

207302 次浏览

Introduction

这可能有很多原因,可以分为以下几节:

  • 将 servlet 类放在 package
  • url-pattern中设置 servlet URL
  • @WebServlet works only on Servlet 3.0 or newer
  • javax.servlet.*在 Servlet 5.0或更新版本中不再工作
  • 确保在构建的 WAR 中存在已编译的 *.class文件
  • 在没有任何 JSP/HTML 页面的情况下单独测试 servlet
  • 使用域相关 URL 从 HTML 引用 servlet
  • 在 HTML 属性中使用直引号

将 servlet 类放在 package

首先,将 servlet 类放在 Javapackage中。您应该将公共可重用的 Java 类放在一个包中,否则它们对于包中的类(如服务器本身)是不可见的。这样可以消除特定于环境的潜在问题。无包 servlet 只能在特定的 Tomcat + JDK 组合中工作,这一点永远不应该被依赖。

对于“普通”IDE 项目,该类需要放置在其包结构中的“ Java 源”文件夹中,没有放置在“ Web Content”文件夹中,该文件夹用于 Web 文件,如 JSP。下面是在 领航员视图中看到的默认 Eclipse 动态网页计划的文件夹结构示例(默认情况下,“ Java 源”文件夹位于此类项目中,由 src文件夹表示) :

EclipseProjectName
|-- src
|    `-- com
|         `-- example
|              `-- YourServlet.java
|-- WebContent
|    |-- WEB-INF
|    |    `-- web.xml
|    `-- jsps
|         `-- page.jsp
:

在 Maven 项目的情况下,类需要放置在它的包结构内的 main/java,因此 没有 main/resources这是用于非类文件的和绝对也 没有 main/webapp,这是为网络文件。下面是 Eclipse 的 领航员视图中默认 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

The servlet URL is specified as the "URL pattern" of the servlet mapping. It's absolutely not per definition the classname/filename of the servlet class. The URL pattern is to be specified as value of @WebServlet annotation.

package com.example; // Use a package!


import jakarta.servlet.annotation.WebServlet; // or javax.*
import jakarta.servlet.http.HttpServlet; // or javax.*


@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 和/xyz/{ value }/test 之类的路径参数,如何在 web.xml 中映射?

请注意,在尝试拥有“前端控制器”时,使用 /*/的 Servlet URL 模式被认为是一种不好的做法。因此,不要滥用这些 URL 模式来试图捕获所有 URL。有关详细说明,请参阅 Servlet 映射 url 模式中/和/* 的区别

@WebServlet只能在 Servlet 3.0或更新版本上工作

为了使用 @WebServlet,您只需要确保您的 web.xml文件(如果有的话(它是可选的,因为 Servlet 3.0))声明符合 Servlet 3.0 + 版本 因此 < em > not 符合例如2.5版本或更低版本。它也绝对不应该有任何 <!DOCTYPE>线。下面是一个兼容 Servlet 6.0的版本(与 Tomcat 10.1 + ,WildFly 27 + (预览版) ,GlassFish/Payara 7 + 等等相匹配) :

<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0"
>
<!-- Config here. -->
</web-app>

And below is a Servlet 5.0 compatible one (which matches Tomcat 10.0.x, WildFly 22+ (Preview), GlassFish/Payara 6+, etc).

<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
>
<!-- Config here. -->
</web-app>

And below is a Servlet 4.0 compatible one (which matches Tomcat 9+, WildFly 11+, GlassFish/Payara 5+, etc).

<?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;


import javax.servlet.http.HttpServlet;


public class YourServlet extends HttpServlet {
// ...
}

然后像下面这样在 web.xml中注册 servlet:

<servlet>
<servlet-name>yourServlet</servlet-name>
<servlet-class>com.example.YourServlet</servlet-class> <!-- Including the package thus -->
</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或更新版本中不再工作

自 JakartaEE 9/Servlet 5.0(Tomcat 10、 TomEE 9、 WildFly 22 Preview、 GlassFish 6、 Payara 6、 Liberty 22等)以来,javax.*包已被重命名为 jakarta.*包。

In other words, please make absolutely sure that you don't randomly put JAR files of a different server in your WAR project such as tomcat-servlet-api-9.x.x.jar merely in order to get the javax.* package to compile. This will only cause trouble. Remove it altogether and edit the imports of your servlet class from

import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;

import jakarta.servlet.*;
import jakarta.servlet.annotation.*;
import jakarta.servlet.http.*;

如果你正在使用 Maven,你可以找到适合 Tomcat 10 + 、 Tomcat 9-、 JEE 9 + 和 JEE 8-的 pom.xml声明的例子: 如何在 Tomcat 的 Maven pom.xml 中正确配置 JakartaEE 库?另一种方法是将服务器降级到更老的版本,例如从 Tomcat 10降级到 Tomcat 9或更老的版本,但这显然不是推荐的方法。

确保在构建的 WAR 中存在已编译的 *.class文件

如果您正在使用 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 Status 500

实例化 servlet 类 com.example.YourServlet 时出错

在服务器日志中找到 java.lang.ClassNotFoundException: com.example.YourServlet,然后是 java.lang.NoClassDefFoundError: com.example.YourServlet,接着是 jakarta.servlet.ServletException: Error instantiating servlet class com.example.YourServlet

验证 servlet 是否正确编译并放置在类路径中的一个简单方法是让构建工具生成一个 WAR 文件(例如,在 Eclipse 中右键单击 project,导出 > WAR 文件) ,然后使用 ZIP 工具检查其内容。如果在 /WEB-INF/classes中缺少 servlet 类,或者导出导致错误,那么项目配置不当,或者一些 IDE/项目配置缺省值被错误地恢复(例如,在 Eclipse 中禁用了 项目 > 自动生成)。

您还需要确保项目图标没有指示构建错误的红色十字。您可以在 问题视图(窗口 > 显示视图 > 其他..。)中找到确切的错误。通常错误消息是很好的谷歌。如果您不知道,最好是从头开始重新启动,不要触摸任何 IDE/项目配置默认值。如果您正在使用 Eclipse,您可以在 如何在 Eclipse 项目中导入 javax.servlet/jakarta.servlet API?中找到指令

在没有任何 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: 此 URL 不支持 HTTP 方法 GET”错误(这仍然比404好,因为405表明实际上已经找到了 servlet 本身)。

重写 service()是一种糟糕的做法,除非你正在重新发明一个 MVC 框架ーー如果你刚刚开始使用 servlet,并且对当前问题中描述的问题一无所知,那么重写 service()是不太可能的;)另见 基于 Web 的应用程序设计模式

无论如何,如果 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://方案,那么它就变成了相对于 current URL,就像你在你的网页浏览器的地址栏中看到的那样。因此,它与服务器的 WAR 文件夹结构中的 JSP/HTML 文件位置完全不相关,许多初学者似乎认为这一点。

因此,假设带有 HTML 表单的 JSP 页面是由 http://localhost:8080/contextname/jsps/page.jsp打开的(因此 not是由 file://...打开的) ,并且您需要向位于 http://localhost:8080/contextname/servlet中的 servlet 提交,这里有几种情况(注意,您可以在这里用 <a href><img src><script src>等安全地替换 <form action>) :

  • 表单操作提交一个带有前导斜杠的 URL。

      <form action="/servlet">
    

    前面的斜杠 /使 URL 相对于域,因此表单将提交到

      http://localhost:8080/servlet
    

    但这可能会导致404,因为它在错误的上下文。


  • 表单操作提交没有前导斜杠的 URL。

      <form action="servlet">
    

    这使得 URL 相对于当前 URL 的当前文件夹,因此表单将提交到

      http://localhost:8080/contextname/jsps/servlet
    

    但这可能会导致一个404,因为它在错误的文件夹中。


  • Form action submits to an URL which goes one folder up.

      <form action="../servlet">
    

    这将向上放置一个文件夹(与本地磁盘文件系统路径完全相同!),因此表格将提交给

      http://localhost:8080/contextname/servlet
    

    这个一定能行!


  • 然而,规范的方法是使 URL 域相关,这样当您碰巧将 JSP 文件移动到另一个文件夹时,就不需要再次修复 URL。

      <form action="${pageContext.request.contextPath}/servlet">
    

    这将产生

      <form action="/contextname/servlet">
    

    因此它总是提交到正确的 URL。


在 HTML 属性中使用直引号

You need to make absolutely sure you're using straight quotes in HTML attributes like action="..." or action='...' and thus 没有 curly quotes like action=”...” or action=’...’. Curly quotes are not supported in HTML and they will simply become part of the value. Watch out when copy-pasting code snippets from blogs! Some blog engines, notably Wordpress, are known to by default use so-called "smart quotes" which thus also corrupts the quotes in code snippets this way. On the other hand, instead of copy-pasting code, try simply typing over the code yourself. Additional advantage of actually getting the code through your brain and fingers is that it will make you to remember and understand the code much better in long term and also make you a better developer.

参见:

HTTP 状态404错误的其他情况:

Solution for HTTP Status 404 in NetBeans IDE: 右键单击您的项目并转到您的项目属性,然后单击 run,然后输入您的项目相对 URL,如 index.jsp

  1. Project->Properties
  2. 点击 Run
  3. 相对 URL:/index.jsp (选择项目根 URL)

enter image description here

场景 # 1: You 不小心被重新部署了 from the command line while tomcat was 已经在跑了

Short Answer: Stop Tomcat, 删除目标文件夹, mvn package, then re-deploy


场景 # 2: request.getRequestDispatcher (“ 文件名.jsp”)

简短回答: 检查文件名 拼写,确保 案件是正确的。


场景 # 3: 未发现类异常 (Answer put here because: Question# 17982240 ) (对于 tomcat 中的 servlet,使用 eclipse 时会出现 java.lang. ClassNotFoundException) (was marked as duplicate and directed me here )

简短回答 # 3.1: web.xml 在 servlet-class 标记中有错误的包路径。

简短回答 # 3.2: java 文件有错误的导入语句。


情景 # 1的进一步细节如下:


第1集: 停止雄猫

  • 选项1: 在终端中通过 CTRL + C。
  • 选项2: (在 tomcat 仍在运行时关闭终端)
  • ————2.1: 按: Windows + R—— > 输入: “ 服务,理学硕士
  • ——————2.2: 在列表的 Name 列中查找“ Apache Tomcat # . # Tomcat #”。
  • ——————2.3: 右击—— > “ stop

2: 删除“目标”文件夹。 (mvn clean 在这里帮不了你)

3: mvn 软件包

4: 这里是你的部署命令

(我的文章是 java-jar 目标/依赖性/webapp-runner.jar ——端口5190 target/* . war)

返回文章页面完整故事:


意外地打开了一个新的 git-bash 窗口,然后 试图为我的 heroku 项目部署一个.war 文件:

Java-jar 目标/依赖性/webapp-runner.jar ——端口5190 target/* . war

在部署失败后,我意识到我打开了两个 git-bash 窗口, 和 没有使用 CTLR + C 来停止以前的部署

我见到了:

HTTP Status 404 – Not Found Type Status Report

Message/if-Student-test. jsp

Description The origin server did not find a current representation 或不愿意透露目标资源 存在。

Apache Tomcat/8.5.31

Below is further details for Scenario #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:

You put the wrong "包裹" statement 在 myClass.java 文件的顶部。

例如:

文件在“ 我的东西”文件夹中

你错误地写道:

package com.my_stuff

这很棘手,因为:

1: The maven build (mvn package) will not report any errors here.

2: web.xml 中的 servlet-class 行可以有 CORRECT 包路径。例如:

<servlet-class>
my_stuff.MyClass
</servlet-class>

堆栈使用方法: 记事本 + + + GitBash + 玛文 + Heroku 网络应用程序运行器 + Tomcat9 + 视窗10:

我的问题是我的方法缺少@RequestBody 注释。在添加注释之后,我不再收到404异常。

执行以下两个步骤。我希望它能够在 java servlet 应用程序开发过程中解决 tomcat 服务器中的“404找不到”问题。

第一步: 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

我删除了旧的 Web 库,比如 Spring 框架库。并建立一个新的路径图书馆。那就成功了。

请检查 上下文根不能为空

如果你使用 Eclipse:
右键单击 ,选择 物业,然后选择 网站项目设置。勾选 < strong > 上下文根不能为空

这是条老线索,但我在别处没找到,还有一种可能性:

如果使用的是 Servlet-api 3.0 + ,那么 web.xml 必须包含 metadata-complete="true"属性

enter image description here

这告诉 tomcat 使用 web.xml中给出的数据而不是使用 @WebServlet注释来映射 servlet。

首先,作为管理员运行 IDE。然后,右键单击项目文件夹-> ProjectFacets,并确保 JavaVersion 设置正确。在我的电脑上。(例1.8)现在应该可以了。

不要仅仅使用 cmd 启动服务器,例如 Wildfly。它必须在 IDE 中启动,现在访问您的本地主机 URL。例子: http://localhost:8080/HelloWorldServlet/HelloWorld

对我有效的修复方法是(如果您使用 Maven) : 右键单击您的项目,Maven-> Update project。这可能会给 JDK 和其他库(在我的例子中是 MySQL 连接器)带来一些其他错误,但是一旦修复了它们,原来的问题就应该修复了!

如果您希望使用 javascript 打开一个 servlet,而不使用“ form”和“ commit”按钮,这里有以下代码:

var button = document.getElementById("<<button-id>>");
button.addEventListener("click", function() {
window.location.href= "<<full-servlet-path>>" (eg. http://localhost:8086/xyz/servlet)
});

关键:

1) ton-id: 在 html/jsp 文件中给按钮的‘ id’标记。

2) full-servlet-path: 单独运行 servlet 时在浏览器中显示的路径

在 web.xml 中映射是我所做的:-

  1. 如果有另一个包为新的方案,那么我们必须提到:-

packagename.filename between opening and closing of servlet-class tag in xml file.

  1. 如果您在 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")

如果这里有人正在使用 MySQL,并且觉得前一天代码还在工作,但是现在不工作了,那么我想你必须打开 MySQL CLI 或 MySQL Workbench,并且只连接到数据库一次。一旦连接上数据库,那么数据库也会连接到 Java 应用程序。我曾经遇到过 Hibernate 方言的错误,说 com.mysql.jdbc 有问题。司机。我认为 MySQL 在某些计算机上存在启动问题。这个问题解决了。

如果您是一名学生,刚接触 Java,那么您的 web.xml 文件可能会出现一些问题。

  1. Try removing the web.xml file.
  2. 其次,检查您的路径变量是否设置正确。
  3. 重新启动 tomcat 服务器或您的电脑。

你的问题一定会得到解决。

Check if you have entered the correct URL Mapping as specified in the Web.xml

例如:

在 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>

这个代码片段所做的是 <url-pattern>/theController</url-pattern>将设置名称,这个名称将用于通过 URL 从前端(例如: form)调用 servlet。因此,当您在前端引用 servlet 时,为了确保请求到达 servlet“ ControllerA”,它应该从表单中引用指定的 URL 模式“ theController”。

例如:

<form action="theController" method="POST">
</form>

我也面临着这个问题,当我访问一个 URL 模式时,我收到了一个404,我知道这个 URL 模式链接到了一个 Servlet。原因是我有2个 Servlet,它们的@WebServletname参数设置为相同的字符串。

@WebServlet(name = "ServletName", urlPatterns = {"/path"})
public class ServletName extends HttpServlet {}
@WebServlet(name = "ServletName", urlPatterns = {"/other-path"})
public class OtherServletName extends HttpServlet {}

这两个 name参数是相同的。如果使用 name 参数,请确保它们与应用程序上的所有其他 Servlet 相比是唯一的。

我也有同样的问题。尝试了所有这一切,但没有帮助。我设法通过在 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>

如果你正在使用 IntelliJ,这就是为我修复它的方法:

转到 Tomcat 配置: enter image description here

配置 > 部署选项卡 enter image description here

向下滚动并将 /添加到 ApplicationContext 下拉列表中 enter image description here

我也有同样的问题。我当时正在开发一个基于 mvc 的 REST API,其中没有显式的 html 配置或文件。API 使用了 Swagger 来生成一个用户界面。问题始于我介绍的斯威格版本“3.0.0”。我又回到了斯威格的“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>