servlet返回“http状态404请求的资源(/servlet)不可用”

htzpubme  于 2021-09-29  发布在  Java
关注(0)|答案(1)|浏览(470)

在我的数据库中,jsp文件中有一个html表单 WebContent/jsps 文件夹。我有一个servlet类 servlet.java 在我的默认包中 src 文件夹。在我的 web.xml 它被Map为 /servlet .
我已经尝试了几个网址 action html表单的属性:

<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状态404-未找到

消息:/servlet
描述:源服务器找不到目标资源的当前表示形式,或者不愿意透露存在该表示形式
为什么它不起作用?

ukdjmx9f

ukdjmx9f1#

导言

这可能有很多原因,这些原因在以下章节中进行了分解:
将servlet类放入 package 在中设置servlet url
url-pattern @WebServlet 仅适用于servlet 3.0或更新版本 javax.servlet.* 在servlet 5.0或更新版本中不再工作
确保已编译 *.class 文件存在于内置war中
在没有任何jsp/html页面的情况下单独测试servlet
使用域相对url从html引用servlet
在html属性中使用直接引号

将servlet类放入包中

首先,将servlet类放在java中 package . 您应该始终将可公开重用的java类放在包中,否则它们对包中的类(例如服务器本身)是不可见的。这样可以消除潜在的特定于环境的问题。无包servlet只能在特定的tomcat+jdk组合中工作,这是不应该依赖的。
对于“普通”ide项目,类需要放在其包结构中的“java源代码”文件夹中,而不是放在“web内容”文件夹中,该文件夹用于jsp等web文件。下面是一个默认eclipse动态web项目的文件夹结构示例,如navigator视图中所示(默认情况下,“java sources”文件夹位于该项目中,由 src 文件夹):

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

对于maven项目,需要将类放置在其内部的包结构中 main/java 因此并非如此 main/resources ,这是针对非类文件的,绝对不是 main/webapp ,这是用于web文件的。下面是在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模式中设置servlet url

servlet url被指定为servletMap的“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/* 相反另请参见servlet和路径参数,如/xyz/{value}/test,如何在web.xml中Map?

@webservlet仅适用于servlet 3.0或更新版本

为了使用 @WebServlet ,您只需确保 web.xml 文件(如果有)(由于servlet 3.0是可选的)被声明为符合servlet 3.0+版本,因此不符合servlet 2.5或更低版本。下面是一个与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 {
    // ...
}

并在中注册servlet web.xml 这样地:

<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的配置将覆盖基于注解的配置。

servlet.*在servlet 5.0或更新版本中不再工作

自雅加达ee 9/servlet 5.0(tomcat 10、tomee 9、wildfly 22预览版、glassfish 6、payara 6、liberty 22等)以来 javax.* 包已重命名为 jakarta.* 包裹
换句话说,请绝对确保不要仅仅为了获得 javax.* 要编译的包。这只会带来麻烦。将其全部删除,并从中编辑servlet类的导入

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

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

如果您正在使用maven,您可以找到适当的示例 pom.xml tomcat 10+、tomcat 9-、jee 9+和jee 8的声明-在这个回答中:tomcat将servlet转换为javax.servlet.servlet,而不是jakarta.servlet.http.httpservlet

确保编译的*.class文件存在于内置war中

如果您使用的是eclipse和/或maven之类的构建工具,那么您需要绝对确保编译后的servlet类文件驻留在它的包结构中 /WEB-INF/classes 生成的war文件的文件夹。万一 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中右键单击项目,导出>war文件),然后使用zip工具检查其内容。如果中缺少servlet类 /WEB-INF/classes ,或者如果导出导致错误,则说明项目配置不正确,或者错误地恢复了某些ide/项目配置默认值(例如,在eclipse中禁用了project>build automatically)。
您还需要确保项目图标没有表示生成错误的红十字。您可以在问题视图(窗口>显示视图>其他…)中找到确切的错误。通常错误消息是很好的googlable。若你们并没有任何线索,最好是从头开始,不要碰任何ide/项目配置默认值。如果您正在使用eclipse,您可以在如何在eclipse项目中导入javax.servlet/jakarta.servlet api中找到说明?

在没有任何jsp/html页面的情况下单独测试servlet

如果服务器运行在 localhost:8080 ,并且战争成功地部署在 /contextname (默认为ide项目名称,区分大小写!),servlet没有初始化失败(读取服务器日志中的任何部署/servlet成功/失败消息以及实际的上下文路径和servletMap),然后是url模式为的servlet /servlet 可于 http://localhost:8080/contextname/servlet .
您可以直接在浏览器的地址栏中输入它,以不受干扰的方式进行测试。如果是 doGet() 正确重写和实现,然后您将在浏览器中看到其输出。或者如果你没有 doGet() 或者如果它不正确地调用 super.doGet() ,则会显示“http 405:http method get不受此url支持”错误(这仍然比404好,因为405是实际找到servlet本身的证据)。
最重要的 service() 这是一种糟糕的做法,除非您正在重新创建一个mvc框架——如果您刚开始使用servlet,并且对当前问题中描述的问题一无所知,那么这是不可能的;)另请参见基于web的应用程序的设计模式。
无论如何,如果servlet在进行独立测试时已经返回404,那么尝试使用html表单是完全没有意义的。因此,从逻辑上讲,在关于servlet 404错误的问题中包含任何html表单也是毫无意义的。

使用域相对url从html引用servlet

一旦您验证了servlet在单独调用时工作正常,那么就可以进入html。至于html表单的具体问题 <form action> 值必须是有效的url。这同样适用于 <a href> . 您需要了解绝对/相对URL是如何工作的。你知道,url是一个网址,你可以在webbrowser的地址栏中输入/查看。如果将相对url指定为表单操作,即没有 http:// 方案,然后它将成为相对于当前url的,如您在webbrowser的地址栏中看到的。因此,它与服务器war文件夹结构中的jsp/html文件位置绝对不是像许多初学者所认为的那样相关。
因此,假设带有html表单的jsp页面是由 http://localhost:8080/contextname/jsps/page.jsp (因此不是通过 file://... ),您需要提交到位于 http://localhost:8080/contextname/servlet ,以下是几种情况(请注意,您可以安全地替换 <form action> 具有 <a href> 此处):
表单操作提交到带有前导斜杠的url。

<form action="/servlet">

前导斜杠 / 使url相对于域,因此表单将提交到

http://localhost:8080/servlet

但这可能会导致404,因为它在错误的上下文中。
表单操作提交到不带前导斜杠的url。

<form action="servlet">

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

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

但这可能会导致404,因为它位于错误的文件夹中。
表单操作提交到一个url,该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='...' 因此不是像这样的 curl 引号 action=”...”action=’...’ . html中不支持 curl 引号,它们只会成为值的一部分。从博客复制粘贴代码片段时要小心!一些b

相关问题