O servlet retorna “Status HTTP 404 O recurso solicitado (/ servlet) não está disponível”

95

Eu tenho um formulário HTML em um arquivo JSP na minha WebContent/jspspasta. Eu tenho uma classe de servlet servlet.javaem meu pacote padrão na srcpasta. No meu web.xmlestá mapeado como /servlet.

Eu tentei vários URLs no actionatributo do formulário HTML:

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

Mas nenhum desses funciona. Todos eles continuam retornando um erro HTTP 404 como abaixo no Tomcat 6/7/8:

Status HTTP 404 - / servlet

Descrição : o recurso solicitado (/ servlet) não está disponível.

Ou como abaixo no Tomcat 8.5 / 9:

Status HTTP 404 - não encontrado

Mensagem : / servlet

Descrição : o servidor de origem não encontrou uma representação atual para o recurso de destino ou não está disposto a divulgar que existe uma

Por que não está funcionando?

pongahead
fonte

Respostas:

127

Coloque a classe servlet em um package

Em primeiro lugar, coloque a classe servlet em um Java package. Você deve sempre colocar classes Java reutilizáveis ​​publicamente em um pacote, caso contrário, elas são invisíveis para as classes que estão em um pacote, como o próprio servidor. Dessa forma, você elimina possíveis problemas específicos do ambiente. Servlets sem pacote funcionam apenas em combinações específicas de Tomcat + JDK e nunca se deve confiar nisso.

No caso de um projeto IDE "simples", a classe precisa ser colocada em sua estrutura de pacote dentro da pasta "Recursos Java" e, portanto, não "Conteúdo da Web", isto é para arquivos da web como JSP. Abaixo está um exemplo da estrutura de pastas de um projeto da Web dinâmico Eclipse padrão , conforme visto na visualização do Navegador :

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

No caso de um projeto Maven, a classe precisa ser colocada em sua estrutura de pacote dentro main/java e, portanto, nãomain/resources , por exemplo , isso é para arquivos não pertencentes à classe . Abaixo está um exemplo da estrutura de pastas de um projeto Maven webapp padrão, conforme visto na visualização Navigator do Eclipse :

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

Observe que a /jspssubpasta não é estritamente necessária. Você pode até mesmo prescindir dele e colocar o arquivo JSP diretamente na raiz webcontent / webapp, mas estou apenas retomando sua pergunta.

Definir o URL do servlet em url-pattern

O URL do servlet é especificado como o "padrão de URL" do mapeamento do servlet. Não é absolutamente por definição o nome da classe / nome do arquivo da classe servlet. O padrão de URL deve ser especificado como valor de @WebServletanotação.

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

Caso queira oferecer suporte a parâmetros de caminho como /servlet/foo/bar, use um padrão de URL de /servlet/*. Veja também Servlet e parâmetros de caminho como / xyz / {value} / test, como mapear em web.xml?

@WebServlet funciona apenas no Servlet 3.0 ou mais recente

Para usar @WebServlet, você só precisa se certificar de que seu web.xmlarquivo, se houver (é opcional desde o Servlet 3.0), é declarado conforme a versão Servlet 3.0+ e, portanto, não conforme, por exemplo, versão 2.5 ou inferior . Abaixo está um Servlet 4.0 compatível (que combina com Tomcat 9+, WildFly 11+, 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>

Ou, caso você ainda não esteja no Servlet 3.0+ (por exemplo, Tomcat 6 ou mais antigo), remova a @WebServletanotação.

package com.example;

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

E registre o servlet web.xmlassim:

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

Observe, portanto, que você não deve usar as duas maneiras. Use configuração baseada em anotação ou configuração baseada em XML. Quando você tiver ambos, a configuração baseada em XML substituirá a configuração baseada em anotação.

Verificando a construção / implantação

Caso você esteja usando uma ferramenta de construção como Eclipse e / ou Maven, você precisa ter certeza absoluta de que o arquivo de classe do servlet compilado reside em sua estrutura de pacote na /WEB-INF/classespasta do arquivo WAR produzido. No caso de package com.example; public class YourServlet, deve estar localizado em /WEB-INF/classes/com/example/YourServlet.class. Caso contrário, você enfrentará no caso de @WebServlettambém um erro 404, ou no caso de <servlet>um erro HTTP 500 como abaixo:

HTTP Status 500

Erro ao instanciar a classe de servlet com.example.YourServlet

E localize no log do servidor a java.lang.ClassNotFoundException: com.example.YourServlet, seguido por a java.lang.NoClassDefFoundError: com.example.YourServlet, por sua vez seguido por javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet.

Uma maneira fácil de verificar se o servlet está compilado corretamente e colocado no classpath é permitir que a ferramenta de construção produza um arquivo WAR (por exemplo, clique com o botão direito do mouse em projeto, Exportar> arquivo WAR no Eclipse) e inspecione seu conteúdo com uma ferramenta ZIP. Se a classe do servlet estiver ausente /WEB-INF/classesou se a exportação causar um erro, o projeto está mal configurado ou alguns padrões de configuração do IDE / projeto foram revertidos por engano (por exemplo, Projeto> Compilar automaticamente foi desativado no Eclipse).

Você também precisa se certificar de que o ícone do projeto não tem uma cruz vermelha indicando um erro de construção. Você pode encontrar o erro exato na visualização Problemas ( Janela> Mostrar Visualização> Outro ... ). Normalmente, a mensagem de erro é boa Googlable. Caso você não tenha ideia, o melhor é reiniciar do zero e não tocar em nenhum padrão de configuração de IDE / projeto. Caso esteja usando o Eclipse, você pode encontrar instruções em Como faço para importar a API javax.servlet no meu projeto Eclipse?

Testando o servlet individualmente

Contanto que o servidor seja executado localhost:8080e o WAR seja implantado com sucesso em um caminho de contexto /contextname(cujo padrão é o nome do projeto IDE, diferencia maiúsculas de minúsculas!) E o servlet não falhou em sua inicialização (leia os logs do servidor para qualquer implantação / mensagens de sucesso / falha do servlet e o caminho de contexto real e mapeamento do servlet), então um servlet com padrão de URL de /servletestá disponível em http://localhost:8080/contextname/servlet.

Você pode simplesmente inseri-lo diretamente na barra de endereços do navegador para testá-lo individualmente. Se doGet()for substituído e implementado corretamente, você verá sua saída no navegador. Ou se você não tiver nenhum doGet()ou se ele chamar incorretamente super.doGet(), um erro " HTTP 405: o método HTTP GET não é compatível com este URL " será mostrado (que ainda é melhor do que um 404, pois um 405 é uma evidência de que o servlet se é realmente encontrado).

Substituir service()é uma prática ruim, a menos que você esteja reinventando uma estrutura MVC - o que é muito improvável se você está apenas começando com servlets e não tem noção do problema descrito na pergunta atual;) Consulte também Aplicativos baseados na web de Padrões de Design .

Independentemente disso, se o servlet já retorna 404 quando testado individualmente, então é totalmente inútil tentar com um formulário HTML. Logicamente, portanto, também é totalmente inútil incluir qualquer formulário HTML em perguntas sobre erros 404 de um servlet.

Referência ao URL do servlet em HTML

Depois de verificar se o servlet funciona bem quando invocado individualmente, você pode avançar para o HTML. Quanto ao seu problema concreto com o formulário HTML, o <form action>valor precisa ser um URL válido. O mesmo se aplica a <a href>. Você precisa entender como funcionam os URLs absolutos / relativos. Você sabe, um URL é um endereço da web que você pode inserir / ver na barra de endereços do navegador. Se você estiver especificando uma URL relativa como ação de formulário, ou seja, sem o http://esquema, ela se tornará relativa à URL atual, conforme você vê na barra de endereços do navegador. Portanto, não é absolutamente relativo à localização do arquivo JSP / HTML na estrutura de pastas WAR do servidor, como muitos iniciantes parecem pensar.

Portanto, supondo que a página JSP com o formulário HTML seja aberta por http://localhost:8080/contextname/jsps/page.jspe você precise enviar a um servlet localizado em http://localhost:8080/contextname/servlet, aqui estão vários casos (observe que você pode substituir <form action>com segurança por <a href>aqui):

  • A ação do formulário é enviada para um URL com uma barra inicial.

    <form action="/servlet">

    A barra inicial /torna o URL relativo ao domínio, portanto, o formulário será enviado para

    http://localhost:8080/servlet

    Mas isso provavelmente resultará em um 404, pois está no contexto errado.


  • A ação do formulário é enviada para um URL sem uma barra inicial.

    <form action="servlet">

    Isso torna o URL relativo à pasta atual do URL atual, portanto, o formulário será enviado para

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

    Mas isso provavelmente resultará em um 404, pois está na pasta errada.


  • A ação do formulário é submetida a um URL que sobe uma pasta.

    <form action="../servlet">

    Isso irá subir uma pasta (exatamente como nos caminhos do sistema de arquivos do disco local!), Portanto, o formulário será enviado para

    http://localhost:8080/contextname/servlet

    Este deve funcionar!


  • A abordagem canônica, entretanto, é tornar a URL relativa ao domínio, para que você não precise corrigir as URLs novamente quando mover os arquivos JSP para outra pasta.

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

    Isso vai gerar

    <form action="/contextname/servlet">

    Que, portanto, sempre enviará para o URL correto.


Use aspas retas em HTML

Você precisa ter certeza absoluta de que está usando aspas retas em atributos HTML como action="..."ou action='...'e, portanto, não aspas curvas como action=”...”ou action=’...’. Aspas curtas não são suportadas em HTML e simplesmente se tornarão parte do valor.

Veja também:

Outros casos de erro HTTP Status 404:

BalusC
fonte
1
web-app version = "3.1" usando glassfish, eu poderia testar meu servlet individualmente muito bem quando eu tinha um mapeamento em web.xml E a anotação. Removi o mapeamento e deixei a anotação porque tenho a versão mais recente, mas receberia um erro 404?
SallyRothroat
1
Isso pode acontecer se você incluir o servlet 2.5 ou bibliotecas mais antigas no próprio webapp em vez de depender do tempo de execução de destino para fornecer as bibliotecas do servlet por si só.
BalusC
@xdola: É realmente frágil porque depende do URI do pedido. Basta ler a resposta para a explicação do seu problema e qual é a abordagem correta.
BalusC de
4

Cenário # 1: você acidentalmente reimplantou a partir da linha de comando enquanto o tomcat estava em execução .

Resposta curta: pare o Tomcat, exclua a pasta de destino , o pacote mvn e reimplante


Cenário 2: request.getRequestDispatcher (" MIS_SPELLED_FILE_NAME .jsp")

Resposta curta: Verifique a ortografia do nome do arquivo , certifique-se de que a caixa está correta.


Cenário # 3: exceções de classe não encontrada (resposta colocada aqui porque: Pergunta # 17982240) ( java.lang.ClassNotFoundException para servlet em tomcat com eclipse ) (foi marcado como duplicado e me direcionou aqui)

Resposta curta nº 3.1: web.xml tem caminho de pacote incorreto na tag da classe de servlet.

Resposta curta # 3.2: o arquivo java tem uma declaração de importação errada.


Abaixo estão mais detalhes para o Cenário # 1:


1: Pare o Tomcat

  • Opção 1: Via CTRL + C no terminal.
  • Opção 2: (terminal fechado enquanto o tomcat ainda está em execução)
  • ------------ 2.1: pressione: Windows + R -> digite: " services.msc "
  • ------------ 2.2: Encontre "Apache Tomcat #. # Tomcat #" na coluna Nome da lista.
  • ------------ 2.3: Clique com o botão direito -> " parar "

2: Exclua a pasta "destino". (mvn clean não vai te ajudar aqui)

3: pacote mvn

4: YOUR_DEPLOYMENT_COMMAND_HERE

(Meu: java -jar target / dependency / webapp-runner.jar --port 5190 target / *. War)

História Completa:


Abri acidentalmente uma nova janela git-bash e tentei implantar um arquivo .war para meu projeto heroku via:

java -jar target / dependency / webapp-runner.jar --port 5190 target / *. war

Depois de uma falha na implantação, percebi que havia duas janelas git-bash abertas e não usei CTLR + C para interromper a implantação anterior .

Encontrei-me com:

Status HTTP 404 - Relatório de status do tipo não encontrado

Message /if-student-test.jsp

Descrição O servidor de origem não encontrou uma representação atual para o recurso de destino ou não deseja divulgar que exista.

Apache Tomcat / 8.5.31

Abaixo estão mais detalhes para o Cenário # 3:


CENÁRIO 3.1: O caminho do pacote da classe de servlet está errado em seu arquivo web.xml.

Ele deve CORRESPONDER à instrução do pacote no topo de sua classe de servlet java.

Arquivo: my_stuff / MyClass.java :

   package my_stuff;

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

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

CENÁRIO 3.2:

Você colocou a instrução " pacote " errada no topo do seu arquivo myClass.java.

Por exemplo:

O arquivo está em: pasta " / my_stuff "

Você escreveu por engano:

package com.my_stuff

Isso é complicado porque:

1: A compilação maven (pacote mvn) não relatará erros aqui.

2: a linha da classe de servlet em web.xml pode ter um caminho de pacote CORRETO. Por exemplo:

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

Pilha usada: Notepad ++ + GitBash + Maven + Heroku Web App Runner + Tomcat9 + Windows10 :

JMI MADISON
fonte
Seu AppName.war e, portanto, o nome da pasta explodida não corresponde ao seu nome esperado, por exemplo, quando seu arquivo war é versionado como AppName-1.0-SNAPSHOT.war e você está tentando / AppName /.
jla
0

Solução para HTTP Status 404no NetBeans IDE: Clique com o botão direito do mouse em seu projeto e vá para as propriedades do projeto, clique em executar e insira o URL relativo do projeto como index.jsp.

  1. Projeto-> Propriedades
  2. Clique em Executar
  3. URL relativo: /index.jsp (selecione o URL raiz do projeto)

insira a descrição da imagem aqui

OU Imon
fonte
0

Meu problema era que meu método não tinha a anotação @RequestBody. Depois de adicionar a anotação, não recebi mais a exceção 404.

THE_DOM
fonte
0

Execute as duas etapas a seguir. Espero que isso resolva o problema "404 não encontrado" no servidor tomcat durante o desenvolvimento do aplicativo servlet java.

Passo 1: Right click on the server(in the server explorer tab)->Properties->Switch Location from workspace metadata to tomcat server

Passo 2: Double Click on the server(in the server explorer tab)->Select Use tomcat installation option inside server location menu

Sajal Saha
fonte
0

Removi a antiga biblioteca da web, que são bibliotecas do Spring Framework. E construir um novo caminho para as bibliotecas. Então funciona.

pajarnas
fonte
0

Um tópico antigo, mas como não o encontrei em outro lugar, aqui está mais uma possibilidade:

Se você estiver usando servlet-api 3.0+ , seu web.xml NÃO deve incluir o metadata-complete="true"atributo

insira a descrição da imagem aqui

Isso informa ao tomcat para mapear os servlets usando dados fornecidos em web.xmlvez de usar a @WebServletanotação.

Chaitanya
fonte
0

Em primeiro lugar, execute seu IDE como Admin. Depois disso, clique com o botão direito na pasta do projeto -> Aspectos do projeto e certifique-se de que a versão do Java esteja configurada corretamente. No meu PC. (Por exemplo 1.8) Agora deve funcionar.

Não inicie apenas o seu servidor, por exemplo Wildfly, usando o cmd. Ele deve ser iniciado dentro do IDE e agora visitar a URL do seu host local. Exemplo: http: // localhost: 8080 / HelloWorldServlet / HelloWorld

Selby Khuzwayo
fonte
0

A correção que funcionou para mim é (se você estiver usando Maven): Clique com o botão direito do mouse em seu projeto, Maven -> Atualizar projeto. Isso pode dar a você algum outro erro com o JDK e outras bibliotecas (no meu caso, o conector MySQL), mas depois de corrigi-los, seu problema original deve ser corrigido!

Joseph zhao
fonte
0

Se você gostaria de abrir um servlet com javascript sem usar o 'formulário' e o botão 'enviar', aqui está o seguinte código:

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

Chave:

1) button-id: A tag 'id' que você atribui ao seu botão em seu arquivo html / jsp.

2) full-servlet-path: o caminho que é mostrado no navegador quando você executa o servlet sozinho

matak8s
fonte
0

Mapeamento em web.xml é o que eu fiz: -

  1. Se houver outro pacote feito para o novo programa, devemos mencionar: -

packagename.filename entre a abertura e o fechamento da tag servlet-class no arquivo xml.

  1. Se você estiver mapeando seus arquivos em xml e eles não estiverem funcionando ou mostrando erros, comente na linha de anotação do código nos respectivos arquivos.

Ambos os métodos não funcionam um com o outro, então ou eu uso o método de anotação dos arquivos mencionados quando criamos o servlet ou a forma de mapeamento, então excluo ou comento a linha de anotação. Por exemplo:

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

Comentando a linha de anotação de código no respectivo arquivo, caso o mapeamento em xml seja feito.

//@WebServlet("/FirstServ")
//@WebServlet("/SecondServ")
Sidharth Jain
fonte
-1

Verifique se a raiz de contexto não pode estar vazia .

Se você estiver usando o eclipse:
clique com o botão direito , selecione propriedades e , em seguida , configurações do projeto da web . Verifique a raiz de contexto não pode estar vazio

Wiem Rachman
fonte