El servlet devuelve "Estado HTTP 404 El recurso solicitado (/servlet) no está disponible"

Resuelto pongahead asked hace 12 años • 0 respuestas

Tengo un formulario HTML en un archivo JSP en mi WebContent/jspscarpeta. Tengo una clase de servlet servlet.javaen mi paquete predeterminado en srcla carpeta. En mi web.xmlestá mapeado como /servlet.

Probé varias URL en actionel atributo del formulario HTML:

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

Pero ninguno de esos funciona. Todos siguen devolviendo un error HTTP 404 como el siguiente en Tomcat 6/7/8:

Estado HTTP 404: /servlet

Descripción : el recurso solicitado (/servlet) no está disponible.

O como se muestra a continuación en Tomcat 8.5/9:

Estado HTTP 404: no encontrado

Mensaje : /servlet

Descripción : el servidor de origen no encontró una representación actual para el recurso de destino o no está dispuesto a revelar que existe una.

O como se muestra a continuación en Tomcat 10:

Estado HTTP 404: no encontrado

Tipo : Informe de estado

Mensaje : El recurso solicitado (/servlet) no está disponible

Descripción : el servidor de origen no encontró una representación actual para el recurso de destino o no está dispuesto a revelar que existe una.

¿Por qué no funciona?

pongahead avatar Jul 31 '12 07:07 pongahead
Aceptado

Introducción

Esto puede tener muchas causas que se desglosan en las siguientes secciones:

  • Poner la clase de servlet en unpackage
  • Establecer la URL del servlet enurl-pattern
  • @WebServletfunciona sólo en Servlet 3.0 o más reciente
  • javax.servlet.*ya no funciona en Servlet 5.0 o posterior
  • Asegúrese de que *.classel archivo compilado esté presente en WAR integrado
  • Pruebe el servlet individualmente sin ninguna página JSP/HTML
  • Utilice una URL relativa al dominio para hacer referencia al servlet desde HTML
  • Utilice comillas rectas en atributos HTML

Poner la clase de servlet en unpackage

En primer lugar, coloque la clase de servlet en Java package. Siempre debe colocar clases Java reutilizables públicamente en un paquete; de ​​lo contrario, serán invisibles para las clases que están en un paquete, como el código fuente del propio servidor. De esta manera se eliminan posibles problemas específicos del entorno. Los servlets sin paquetes funcionan solo en combinaciones específicas de Tomcat+JDK y nunca se debe confiar en esto. En caso de que no tenga idea de qué paquete elegir, comience con com.example.

En el caso de un proyecto IDE "simple", la clase debe colocarse en su estructura de paquete dentro de la carpeta "Fuentes Java", no dentro de la carpeta "Contenido web", que es para archivos web como JSP. A continuación se muestra un ejemplo de la estructura de carpetas de un proyecto web dinámico de Eclipse predeterminado como se ve en la vista del Navegador (la carpeta "Fuentes Java" está en dicho proyecto representada de forma predeterminada por srccarpeta):

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

En el caso de un proyecto Maven, la clase debe colocarse en su estructura de paquete interna main/javay, por lo tanto , no main/resources , esto es para archivos que no son de clase y tampoco main/webapp , en absoluto , esto es para archivos web. A continuación se muestra un ejemplo de la estructura de carpetas de un proyecto de aplicación web Maven predeterminado como se ve en la vista Navegador de Eclipse :

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

Tenga en cuenta que la /jspssubcarpeta no es estrictamente necesaria. Incluso puede prescindir de él y colocar el archivo JSP directamente en la raíz del contenido web/aplicación web, pero me estoy ocupando de esto de su pregunta.

Establecer la URL del servlet enurl-pattern

La URL del servlet se especifica como el "patrón de URL" de la asignación de servlet. No es en absoluto, por definición, el nombre de clase/nombre de archivo de la clase de servlet. El patrón de URL debe especificarse como valor de @WebServletanotación.

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.
    // ...
}

En caso de que desee admitir parámetros de ruta como /servlet/foo/bar, utilice un patrón de URL de /servlet/*en su lugar. Consulte también parámetros de ruta y servlet como /xyz/{value}/test, ¿cómo mapear en web.xml?

Tenga en cuenta que se considera una mala práctica utilizar un patrón de URL de servlet /*en /un intento de tener un "controlador frontal". Por lo tanto, no abuse de estos patrones de URL en un intento de capturar todas las URL. Para obtener una explicación detallada, consulte también Diferencia entre / y /* en el patrón de URL de mapeo de servlets .

@WebServletfunciona sólo en Servlet 3.0 o más reciente

Para poder utilizar @WebServlet, debe asegurarse de que su web.xmlarchivo, si lo hay (es opcional desde Servlet 3.0), esté declarado conforme a la versión Servlet 3.0+ y, por lo tanto , no conforme, por ejemplo, a la versión 2.5 o inferior . Tampoco debería tener ninguna <!DOCTYPE>línea. A continuación se muestra uno compatible con Servlet 6.0 (que coincide con Tomcat 10.1+, WildFly 27+ (vista previa), GlassFish/Payara 7+, etc.) en su totalidad:

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

Y a continuación se muestra uno compatible con Servlet 5.0 (que coincide con Tomcat 10.0+, WildFly 22+ (Vista previa), 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>

Y a continuación se muestra uno compatible con Servlet 4.0 (que coincide con 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>

O, en caso de que aún no esté en Servlet 3.0+ (por ejemplo, Tomcat 6 o anterior), elimine la @WebServletanotación (y asegúrese de eliminar también todos los archivos JAR incorrectos o las dependencias de Maven que le permitieron compilar correctamente el código):

package com.example;

import javax.servlet.http.HttpServlet;

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

Y registre el servlet de web.xmlesta manera:

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

Por lo tanto, tenga en cuenta que no debe utilizar ambas formas. Utilice una configuración basada en anotaciones o una configuración basada en XML. Cuando tenga ambos, la configuración basada en XML anulará la configuración basada en anotaciones.

javax.servlet.*ya no funciona en Servlet 5.0 o posterior

Desde Jakarta EE 9/Servlet 5.0 (Tomcat 10, TomEE 9, WildFly 22 Preview, GlassFish 6, Payara 6, Liberty 22, etc.), se javax.*ha cambiado el nombre del paquete a jakarta.*paquete.

En otras palabras, asegúrese absolutamente de no colocar aleatoriamente archivos JAR de un servidor diferente en su proyecto WAR, como tomcat-servlet-api.jar, simplemente para que el javax.*paquete se compile. Esto sólo causará problemas. Elimínelos por completo y edite las importaciones de su clase de servlet desde

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

a

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

En caso de que esté utilizando Maven, puede encontrar ejemplos de pom.xmldeclaraciones adecuadas para Tomcat 10+, Tomcat 9-, JEE 9+ y JEE 8- en esta respuesta: ¿ Cómo configurar correctamente las bibliotecas Jakarta EE en Maven pom.xml para Tomcat? La alternativa es degradar el servidor a una versión anterior, por ejemplo, de Tomcat 10 a Tomcat 9 o anterior, pero claramente esta no es la forma recomendada de hacerlo.

En caso de que esté utilizando Spring en lugar de Jakarta EE, Spring 6 y Spring Boot 3 son las primeras versiones destinadas a Servlet 5.0 y, por lo tanto, también las primeras versiones en utilizar el jakarta.*paquete. Las versiones anteriores todavía usan el javax.*paquete. Ajuste sus importaciones en consecuencia.

Debe asegurarse absolutamente de no tener bibliotecas en conflicto en sus dependencias (ya sea pom.xml o los archivos físicos en /WEB-INF/lib) que incorrectamente permitan compilar correctamente javax.servlet.*. El uso javax.servlet.*debe generar un error de compilación en proyectos orientados al menos a Servlet 5.0+ (es decir, Jakarta EE 9+ o Spring 6+ o Spring Boot 3+).

Asegúrese de que *.classel archivo compilado esté presente en WAR integrado

En caso de que esté utilizando una herramienta de compilación como Eclipse y/o Maven, debe asegurarse absolutamente de que el archivo de clase de servlet compilado resida en su estructura de paquete en la /WEB-INF/classescarpeta del archivo WAR producido. En caso de package com.example; public class YourServlet, deberá estar ubicado en /WEB-INF/classes/com/example/YourServlet.class. De lo contrario, se enfrentará en caso de que @WebServlettambién se produzca un error 404, o en caso de <servlet>un error HTTP 500 como se muestra a continuación:

Estado HTTP 500

Error al crear una instancia de la clase de servlet com.example.YourServlet

Y busque en el registro del servidor a java.lang.ClassNotFoundException: com.example.YourServlet, seguido de a java.lang.NoClassDefFoundError: com.example.YourServlet, seguido a su vez de jakarta.servlet.ServletException: Error instantiating servlet class com.example.YourServlet.

Una manera fácil de verificar si el servlet está correctamente compilado y colocado en classpath es dejar que la herramienta de compilación produzca un archivo WAR (por ejemplo, haga clic derecho en el proyecto, Exportar > Archivo WAR en Eclipse) y luego inspeccione su contenido con una herramienta ZIP. Si falta la clase de servlet en /WEB-INF/classes, o si la exportación causa un error, entonces el proyecto está mal configurado o algunos valores predeterminados de configuración del IDE/proyecto se han revertido por error (por ejemplo, Proyecto > Construir automáticamente se ha deshabilitado en Eclipse).

También debe asegurarse de que el ícono del proyecto no tenga una cruz roja que indique un error de compilación. Puede encontrar el error exacto en la vista Problemas ( Ventana > Mostrar vista > Otro... ). Por lo general, el mensaje de error está bien Googleable. En caso de que no tenga idea, lo mejor es reiniciar desde cero y no tocar ningún valor predeterminado de configuración del IDE/proyecto. En caso de que esté utilizando Eclipse, puede encontrar instrucciones en ¿Cómo importo la API javax.servlet/jakarta.servlet en mi proyecto Eclipse?

Pruebe el servlet individualmente sin ninguna página JSP/HTML

Siempre que el servidor se ejecute en localhost:8080, y que WAR se implemente exitosamente en una ruta de contexto de /contextname(que por defecto es el nombre del proyecto IDE o el nombre del archivo del artefacto de compilación de Maven, ¡distingue entre mayúsculas y minúsculas!), y el servlet no haya fallado en su inicialización ( lea los registros del servidor para ver los mensajes de éxito/error de implementación/servlet y la ruta de contexto real y la asignación de servlet), luego hay un servlet con el patrón de URL /servletdisponible en http://localhost:8080/contextname/servlet.

Puedes ingresarlo directamente en la barra de direcciones del navegador para probarlo individualmente. Si se doGet()anula e implementa correctamente, verá su resultado en el navegador. O si no tiene ninguno doGet()o si llama incorrectamente super.doGet(), se mostrará el error " HTTP 405: el método HTTP GET no es compatible con esta URL " (que sigue siendo mejor que un 404, ya que un 405 es evidencia de que el servlet se encuentra realmente).

Anular service()es una mala práctica, a menos que esté reinventando un marco MVC, lo cual es muy poco probable si recién está comenzando con servlets y no tiene idea del problema descrito en la pregunta actual. Consulte también Patrones de diseño de aplicaciones basadas en web .

Tenga en cuenta que cuando el servlet ya devuelve 404 cuando se prueba individualmente, entonces no tiene sentido intentarlo con un formulario HTML. Lógicamente, tampoco tiene sentido incluir ningún formulario HTML en las preguntas sobre errores 404 de un servlet.

Utilice una URL relativa al dominio para hacer referencia al servlet desde HTML

Una vez que haya verificado que el servlet funciona bien cuando se invoca individualmente, puede avanzar a HTML. En cuanto a su problema concreto con el formulario HTML, el <form action>valor debe ser una URL válida. Lo mismo se aplica a <a href>, <img src>, <script src>, etc. Debe comprender cómo funcionan las URL absolutas/relativas. Ya sabes, una URL es una dirección web que puedes ingresar/ver en la barra de direcciones del navegador web. Si especifica una URL relativa como acción de formulario, es decir, sin el http://esquema, entonces se vuelve relativa a la URL actual como se ve en la barra de direcciones de su navegador web. Por lo tanto, no es en absoluto relativo a la ubicación del archivo JSP/HTML en la estructura de carpetas WAR del servidor, como muchos principiantes parecen pensar.

Entonces, suponiendo que la página JSP con el formulario HTML se abre con http://localhost:8080/contextname/jsps/page.jsp(y por lo tanto no con file://...) y necesita enviarla a un servlet ubicado en http://localhost:8080/contextname/servlet, aquí hay varios casos (tenga en cuenta que aquí puede sustituir de forma segura <form action>con <a href>, <img src>, <script src>, etc.) :

  • La acción del formulario se envía a una URL con una barra diagonal inicial.

      <form action="/servlet">
    

    La barra diagonal inicial /hace que la URL sea relativa al dominio, por lo que el formulario se enviará a

      http://localhost:8080/servlet
    

    Pero esto probablemente resultará en un 404 ya que está en el contexto incorrecto.


  • La acción del formulario se envía a una URL sin una barra diagonal inicial.

      <form action="servlet">
    

    Esto hace que la URL sea relativa a la carpeta actual de la URL actual, por lo que el formulario se enviará a

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

    Pero esto probablemente generará un error 404 ya que está en la carpeta incorrecta.


  • La acción del formulario se envía a una URL que sube una carpeta.

      <form action="../servlet">
    

    Esto subirá una carpeta (¡exactamente como en las rutas del sistema de archivos del disco local!), por lo que el formulario se enviará a

      http://localhost:8080/contextname/servlet
    

    ¡Este debe funcionar!


  • El enfoque canónico, sin embargo, es hacer que la URL sea relativa al dominio para que no necesite corregir las URL una vez más cuando mueva los archivos JSP a otra carpeta.

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

    Esto generará

      <form action="/contextname/servlet">
    

    Por lo tanto, siempre se enviará a la URL correcta.


Utilice comillas rectas en atributos HTML

Debe asegurarse absolutamente de utilizar comillas rectas en atributos HTML como action="..."o action='...'y, por lo tanto, no comillas como action=”...”o action=’...’. Las comillas no son compatibles con HTML y simplemente pasarán a formar parte del valor. ¡Cuidado al copiar y pegar fragmentos de código de blogs! Se sabe que algunos motores de blogs, especialmente Wordpress, utilizan de forma predeterminada las llamadas "comillas tipográficas", lo que también corrompe las comillas en los fragmentos de código de esta manera. Por otro lado, en lugar de copiar y pegar el código, intente simplemente escribir el código usted mismo. La ventaja adicional de pasar el código por el cerebro y los dedos es que le permitirá recordar y comprender el código mucho mejor a largo plazo y también le convertirá en un mejor desarrollador.

Ver también:

  • Nuestra página wiki de servlets : contiene algunos ejemplos de hola mundo
  • Cómo llamar a la clase de servlet desde un formulario HTML
  • doGet y doPost en Servlets
  • ¿Cómo paso el elemento actual al método Java haciendo clic en un hipervínculo o botón en la página JSP?

Otros casos de error HTTP Status 404:

  • Estado HTTP 404: el servlet [ServletName] no está disponible
  • Estado HTTP 404: el recurso solicitado (/ProjectName/) no está disponible
  • Estado HTTP 404: el recurso solicitado (/) no está disponible
  • JSP en /WEB-INF devuelve "Estado HTTP 404 El recurso solicitado no está disponible"
  • Hacer referencia a un recurso ubicado en la carpeta WEB-INF en el archivo JSP devuelve HTTP 404 en el recurso
  • El navegador no puede acceder/encontrar recursos relativos como CSS, imágenes y enlaces cuando llama a un servlet que reenvía a un JSP
BalusC avatar Jul 31 '2012 00:07 BalusC

Escenario n.° 1: accidentalmente volvió a implementar desde la línea de comando mientras Tomcat ya se estaba ejecutando .

Respuesta corta: detenga Tomcat, elimine la carpeta de destino , el paquete mvn y luego vuelva a implementarlo


Escenario n.º 2: request.getRequestDispatcher(" MIS_SPELLED_FILE_NAME .jsp")

Respuesta corta: verifique la ortografía del nombre del archivo y asegúrese de que las mayúsculas y minúsculas sean correctas.


Escenario n.° 3: Excepciones de clase no encontrada (respuesta aquí porque: Pregunta n.° 17982240) ( java.lang.ClassNotFoundException para servlet en Tomcat con eclipse ) (se marcó como duplicado y me dirigió aquí)

Respuesta corta n.º 3.1: web.xml tiene una ruta de paquete incorrecta en la etiqueta de clase de servlet.

Respuesta corta n.º 3.2: el archivo java tiene una declaración de importación incorrecta.


A continuación se muestran más detalles para el Escenario n.° 1:


1: detener Tomcat

  • Opción 1: Vía CTRL+C en la terminal.
  • Opción 2: (terminal cerrada mientras Tomcat aún se ejecuta)
  • ------------ 2.1: presione: Windows+R --> escriba:" servicios.msc "
  • ------------ 2.2: Busque "Apache Tomcat #.# Tomcat#" en la columna Nombre de la lista.
  • ------------ 2.3: Clic derecho --> " detener "

2: Elimine la carpeta "destino". (mvn clean no te ayudará aquí)

3: paquete mvn

4: TU_COMANDO_DEPLOYMENT_AQUÍ

(Mío: java -jar target/dependency/webapp-runner.jar --port 5190 target/*.war )

Historia de fondo completa:


Accidentalmente abrí una nueva ventana de git-bash e intenté implementar un archivo .war para mi proyecto heroku a través de:

java -jar destino/dependencia/webapp-runner.jar --puerto 5190 destino/*.war

Después de un error en la implementación, me di cuenta de que tenía dos ventanas de git-bash abiertas y no había usado CTLR+C para detener la implementación anterior .

Me encontré con:

Estado HTTP 404: Informe de estado de tipo no encontrado

Mensaje /if-student-test.jsp

Descripción El servidor de origen no encontró una representación actual para el recurso de destino o no está dispuesto a revelar que existe.

Apache Tomcat/8.5.31

A continuación se muestran más detalles para el Escenario n.° 3:


ESCENARIO 3.1: La ruta del paquete de clase servlet es incorrecta en su archivo web.xml.

Debería COINCIDIR con la declaración del paquete en la parte superior de su clase de servlet Java.

Archivo: my_stuff/ MyClass.java :

   package my_stuff;

Archivo: PRJ_ROOT/src/main/webapp/WEB-INF/ web.xml

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

ESCENARIO 3.2:

Colocaste la declaración " paquete " incorrecta en la parte superior de tu archivo myClass.java.

Por ejemplo:

El archivo está en: carpeta " /my_stuff "

Escribes por error:

package com.my_stuff

Esto es complicado porque:

1: La compilación maven (paquete mvn) no informará ningún error aquí.

2: la línea de clase de servlet en web.xml puede tener la ruta CORRECTA del paquete. P.ej:

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

Pila utilizada: Notepad++ + GitBash + Maven + Heroku Web App Runner + Tomcat9 + Windows10 :

KANJICODER avatar Jul 16 '2018 06:07 KANJICODER

Compruebe si ha introducido la asignación de URL correcta como se especifica en Web.xml

Por ejemplo:

En web.xml, su declaración de servlet tal vez:

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

Lo que hace este fragmento es <url-pattern>/theController</url-pattern>establecer el nombre que se usará para llamar al servlet desde el front-end (por ejemplo: formulario) a través de la URL. Por lo tanto, cuando hace referencia al servlet en el front-end, para garantizar que la solicitud vaya al servlet "ControllerA", debe hacer referencia al patrón de URL especificado "theController" del formulario.

p.ej:

<form action="theController" method="POST">
</form>
Lakindu Hewawasam avatar Nov 12 '2020 08:11 Lakindu Hewawasam

Si estás usando IntelliJ, esto es lo que me solucionó el problema:

Vaya a la configuración de Tomcat: ingrese la descripción de la imagen aquí

Configuración > Pestaña Implementación ingrese la descripción de la imagen aquí

Desplácese hacia abajo y agregue /al menú desplegable Contexto de la aplicación ingrese la descripción de la imagen aquí

Suitcase Coder avatar Aug 04 '2021 16:08 Suitcase Coder