Servlet返回“HTTP状态404所请求的资源(/ servlet)不可用” [英] Servlet returns "HTTP Status 404 The requested resource (/servlet) is not available"

查看:9118
本文介绍了Servlet返回“HTTP状态404所请求的资源(/ servlet)不可用”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 WebContent / jsps 文件夹中的JSP文件中有一个HTML表单。我在 src 文件夹的缺省包中有一个servlet类 servlet.java 。在我的 web.xml 中,它被映射为 / servlet



我已经在HTML表单的 action 属性中尝试了几个网址:

 < form action =/ servlet> 



< form action = /servlet.java\">



< form action = /src/servlet.java\">



< form action = ../servlet.java\">

但这些都不起作用。它们都会在Tomcat 6/7/8中继续返回像下面这样的HTTP 404错误:

lockquote

HTTP状态404 - / servlet


$ b

描述:请求的资源(/ servlet)不可用。

或者如下面的Tomcat 8.5 / 9:


HTTP状态404 - 未找到



消息:/ servlet



描述:原始服务器未找到当前的表示对于目标资源或者不愿意透露存在的一个存在


为什么它不起作用?

解决方案

将servlet类放入包中



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



对于普通IDE项目,该类需要放在Java Resources文件夹内的包结构中,因此 WebContent,这是针对诸如JSP的网页文件。以下是在 Navigator 视图中看到的默认Eclipse动态Web项目的文件夹结构示例:

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

在Maven项目中,类需要放置在它的包结构中 main / java 因此不是例如 main / resources ,这是针对非类文件的。下面是在Eclipse的 Navigator 视图中看到的默认Maven webapp项目的文件夹结构示例:


$ b

  MavenProjectName 
| - src
| ` - 主
| | - java
| | ` - com
| | ` - 示例
| | ` - YourServlet.java
| | - 资源
| ` - webapp
| | - WEB-INF
| | ` - web.xml
| ` - jsps
| ` - page.jsp

注意 / jsps 子文件夹不是严格必要的。你甚至可以没有它,并将JSP文件直接放在webcontent / webapp root中,但我只是接管你的问题。



将servlet URL设置为 url-pattern



servlet URL被指定为servlet映射的URL模式。绝对不是每个定义的servlet类的类名/文件名。 URL模式将被指定为 @WebServlet 注释的值。

  package com.example; //使用包装! 

@WebServlet(/ servlet)//这是servlet的URL。
public class YourServlet扩展HttpServlet {//必须公开并扩展HttpServlet。
// ...
}

如果您想支持路径参数如 / servlet / foo / bar ,然后使用 / servlet / * 的URL模式。另请参阅 Servlet和路径参数/ xyz / {value} / test,如何在web.xml中映射?
$ b

@WebServlet 仅适用于Servlet 3.0或更新版本



为了使用 @WebServlet ,您只需要确保你的 web.xml 文件(如果有的话)(自Servlet 3.0以来是可选的)被声明为符合Servlet 3.0+版本,因此 not 符合eg 2.5版本或更低版本。下面是一个兼容Servlet 3.1的版本(与Tomcat 8+,WildFly 8+,GlassFish 4+等相匹配)。

 < ;?xml version =1.0encoding =UTF-8?> 
< web-app xmlns:xsi =http://www.w3.org/2001/XMLSchema-instance
xmlns =http://xmlns.jcp.org/xml/ns / javaee
xsi:schemaLocation =http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd
id =WebApp_IDversion =3.1
>
<! - 在这里配置。 - >
< / web-app>

或者,如果您还没有使用Servlet 3.0+(不是Tomcat 7或更新版本,但是Tomcat 6或更旧版本),然后删除 @WebServlet 注释。

  package com.example; 

公共类YourServlet扩展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> <! - 这是servlet的URL。 - >
< / servlet-mapping>

请注意,您不应该同时使用这两种方式。使用基于注释的配置或基于XML的配置。如果两者都有,则基于XML的配置将覆盖基于注释的配置。



验证构建/部署



如果您使用的是Eclipse和/或Maven等构建工具,那么您需要确保编译的servlet类文件驻留在 / 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:实例化servlet类的错误com.example.YourServlet



一种简单的方法来验证servlet是否正确编译并放置在classpath中是让构建工具生成一个WAR文件(例如,Eclipse中的右键项目, Export> WAR file ),然后使用ZIP工具检查其内容。如果 / WEB-INF / classes 中缺少servlet类,那么该项目配置错误或某些IDE /项目配置默认值被错误地还原(例如, Project >自动构建已在Eclipse中禁用)。如果你没有线索,最好是从头开始重新启动,并且不要触及任何IDE /项目配置默认值。

单独测试servlet



假设服务器在 localhost:8080 上运行,并且WAR已成功部署在 / contextname (默认为IDE项目名称,区分大小写!),并且该servlet没有失败其初始化(读取任何部署/ servlet成功/失败消息的服务器日志以及实际的上下文路径和servlet映射),那么一个URL模式为 / servlet 的servlet可以在 http:// localhost:8080 / contextname / servlet

您只需在浏览器的地址栏中直接输入它即可对其进行测试。如果它的 doGet()被正确覆盖和实现,那么你将在浏览器中看到它的输出。或者,如果您没有任何 doGet()或者它错误地调用了 super.doGet(),那么a HTTP 405:HTTP方法GET不受此支持URL 错误将会显示出来(这比404更好,因为405证明了实际上发现了servlet本身)。



覆盖 service()是一个不好的习惯,除非你重新创建了一个MVC框架—如果你刚刚开始使用servlet,并且对当前问题中描述的问题一无所知,这是不太可能的;)另见设计模式基于web的应用程序



无论如何,如果servlet在不知情的情况下已经返回404,那么尝试完全没有意义用HTML表单代替。从逻辑上讲,因此在关于来自servlet的404错误的问题中包含任何HTML表单也完全没有意义。

从HTML引用servlet URL



一旦您验证了servlet在单独调用时工作正常,那么您可以前进到HTML。至于HTML表单的具体问题,< form action> 值需要是一个有效的URL。这同样适用于< a href> 。您需要了解绝对/相对URL的工作方式。您知道,网址是网址,您可以在网页浏览器的地址栏中输入/查看。如果您将相对网址指定为表单操作,即不使用 http:// 方案,那么它将相对于当前 URL你会在你的浏览器的地址栏中看到。因此,许多初学者似乎认为它与服务器的WAR文件夹结构中的JSP / HTML文件位置绝对没有关系。因此,假设带有HTML表单的JSP页面由 http:// localhost:8080 / contextname / jsps / page.jsp 打开,您需要提交给位于 http: // localhost:8080 / contextname / servlet ,这里有几种情况(请注意,您可以安全地将< form action> 替换为<$ c
$ b


  • 表单操作提交到一个URL
    $ b

     < form action =/ servlet> 

    前导斜杠 / 使URL相对到域,这样表单将提交到

      http:// localhost:8080 / servlet 

    但是这可能会导致404错误,因为它处于错误的上下文中。





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

     < form action =servlet> 

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

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

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



    < hr>

  • 表单操作提交给一个文件夹上的URL。


    $ b

     < form action =../ servlet> 

    这会将一个文件夹放在一起(与本地磁盘文件系统路径完全一样!),因此表单将提交到

      http:// localhost:8080 / contextname / servlet 

    这个必须工作!



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

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

    这会产生

     < form action =/ contextname / servlet> 

    因此,它总是会提交到正确的网址。







在HTML中使用直引号



您需要确保你在HTML属性中使用了直接引用,如 action =... action ='...',因此不像 action =... action ='... 。卷曲引号在HTML中不被支持,它们只会成为值的一部分。



另见:





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




I have an HTML form in a JSP file in my WebContent/jsps folder. I have a servlet class servlet.java in my default package in src folder. In my web.xml it is mapped as /servlet.

I have tried several URLs in action attribute of the HTML form:

<form action="/servlet">

<form action="/servlet.java">

<form action="/src/servlet.java">

<form action="../servlet.java">

But none of those work. They all keep returning a HTTP 404 error like below in Tomcat 6/7/8:

HTTP Status 404 — /servlet

Description: The requested resource (/servlet) is not available.

Or as below in Tomcat 8.5/9:

HTTP Status 404 — Not Found

Message: /servlet

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

Why is it not working?

解决方案

Put servlet class in a package

First of all, put the servlet class in a Java package. You should always put publicly reuseable Java classes in a package, otherwise they are invisible to classes which are in a package, such as the server itself. This way you eliminiate potential environment-specific problems. Packageless servlets work only in specific Tomcat+JDK combinations and this should never be relied upon.

In case of a "plain" IDE project, the class needs to be placed in its package structure inside "Java Resources" folder and thus not "WebContent", this is for web files such as JSP. Below is an example of the folder structure of a default Eclipse Dynamic Web Project as seen in Navigator view:

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

In case of a Maven project, the class needs to be placed in its package structure inside main/java and thus not e.g. main/resources, this is for non-class files. Below is an example of the folder structure of a default Maven webapp project as seen in Eclipse's Navigator view:

MavenProjectName
 |-- src
 |    `-- main
 |         |-- java
 |         |    `-- com
 |         |         `-- example
 |         |              `-- YourServlet.java
 |         |-- resources
 |         `-- webapp
 |              |-- WEB-INF
 |              |    `-- web.xml
 |              `-- jsps
 |                   `-- page.jsp
 :

Note that the /jsps subfolder is not strictly necessary. You can even do without it and put the JSP file directly in webcontent/webapp root, but I'm just taking over this from your question.

Set servlet URL in url-pattern

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!

@WebServlet("/servlet") // This is the URL of the servlet.
public class YourServlet extends HttpServlet { // Must be public and extend HttpServlet.
    // ...
}

In case you want to support path parameters like /servlet/foo/bar, then use an URL pattern of /servlet/* instead. See also Servlet and path parameters like /xyz/{value}/test, how to map in web.xml?

@WebServlet works only on Servlet 3.0 or newer

In order to use @WebServlet, you only need to make sure that your web.xml file, if any (it's optional since Servlet 3.0), is declared conform Servlet 3.0+ version and thus not conform e.g. 2.5 version or lower. Below is a Servlet 3.1 compatible one (which matches Tomcat 8+, WildFly 8+, GlassFish 4+, etc).

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1"
>
    <!-- Config here. -->
</web-app>

Or, in case you're not on Servlet 3.0+ yet (not Tomcat 7 or newer, but Tomcat 6 or older), then remove the @WebServlet annotation.

package com.example;

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

And register the servlet instead in web.xml like this:

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

Note thus that you should not use both ways. Use either annotation based configuarion or XML based configuration. When you have both, then XML based configuration will override annotation based configuration.

Verifying the build/deployment

In case you're using a build tool such as Eclipse and/or Maven, then you need to make absolutely sure that the compiled servlet class file resides in its package structure in /WEB-INF/classes folder of the produced WAR file. In case of package com.example; public class YourServlet, it must be located in /WEB-INF/classes/com/example/YourServlet.class. Otherwise you will face in case of @WebServlet also a 404 error, or in case of <servlet> a HTTP 500 error like below:

HTTP Status 500

Error instantiating servlet class com.example.YourServlet

And find in the server log a java.lang.ClassNotFoundException: com.example.YourServlet, followed by a java.lang.NoClassDefFoundError: com.example.YourServlet, in turn followed by javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet.

An easy way to verify if the servlet is correctly compiled and placed in classpath is to let the build tool produce a WAR file (e.g. rightclick project, Export > WAR file in Eclipse) and then inspect its contents with a ZIP tool. If the servlet class is missing in /WEB-INF/classes, then the project is badly configured or some IDE/project configuration defaults have been mistakenly reverted (e.g. Project > Build Automatically has been disabled in Eclipse). In case you have no clue, best is to restart from scratch and do not touch any IDE/project configuration defaults.

Testing the servlet individually

Provided that the server runs on localhost:8080, and that the WAR is successfully deployed on a context path of /contextname (which defaults to the IDE project name, case sensitive!), and the servlet hasn't failed its initialization (read server logs for any deploy/servlet success/fail messages and the actual context path and servlet mapping), then a servlet with URL pattern of /servlet is available at http://localhost:8080/contextname/servlet.

You can just enter it straight in browser's address bar to test it invidivually. If its doGet() is properly overriden and implemented, then you will see its output in browser. Or if you don't have any doGet() or if it incorrectly calls super.doGet(), then a "HTTP 405: HTTP method GET is not supported by this URL" error will be shown (which is still better than a 404 as a 405 is evidence that the servlet itself is actually found).

Overriding service() is a bad practice, unless you're reinventing a MVC framework — which is very unlikely if you're just starting out with servlets and are clueless as to the problem described in the current question ;) See also Design Patterns web based applications.

Regardless, if the servlet already returns 404 when tested invidivually, then it's entirely pointless to try with a HTML form instead. Logically, it's therefore also entirely pointless to include any HTML form in questions about 404 errors from a servlet.

Referencing the servlet URL from HTML

Once you've verified that the servlet works fine when invoked individually, then you can advance to HTML. As to your concrete problem with the HTML form, the <form action> value needs to be a valid URL. The same applies to <a href>. You need to understand how absolute/relative URLs work. You know, an URL is a web address as you can enter/see in the webbrowser's address bar. If you're specifying a relative URL as form action, i.e. without the http:// scheme, then it becomes relative to the current URL as you see in your webbrowser's address bar. It's thus absolutely not relative to the JSP/HTML file location in server's WAR folder structure as many starters seem to think.

So, assuming that the JSP page with the HTML form is opened by http://localhost:8080/contextname/jsps/page.jsp, and you need to submit to a servlet located in http://localhost:8080/contextname/servlet, here are several cases (note that you can safely substitute <form action> with <a href> here):

  • Form action submits to an URL with a leading slash.

    <form action="/servlet">
    

    The leading slash / makes the URL relative to the domain, thus the form will submit to

    http://localhost:8080/servlet
    

    But this will likely result in a 404 as it's in the wrong context.


  • Form action submits to an URL without a leading slash.

    <form action="servlet">
    

    This makes the URL relative to the current folder of the current URL, thus the form will submit to

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

    But this will likely result in a 404 as it's in the wrong folder.


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

    <form action="../servlet">
    

    This will go one folder up (exactly like as in local disk file system paths!), thus the form will submit to

    http://localhost:8080/contextname/servlet
    

    This one must work!


  • The canonical approach, however, is to make the URL domain-relative so that you don't need to fix the URLs once again when you happen to move the JSP files around into another folder.

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

    This will generate

    <form action="/contextname/servlet">
    

    Which will thus always submit to the right URL.


Use straight quotes in HTML

You need to make absolutely sure you're using straight quotes in HTML attributes like action="..." or action='...' and thus not curly quotes like action="..." or action=’...’. Curly quotes are not supported in HTML and they will simply become part of the value.

See also:

Other cases of HTTP Status 404 error:

这篇关于Servlet返回“HTTP状态404所请求的资源(/ servlet)不可用”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆