Descritor de implantação: web.xml

ID da região

O REGION_ID é um código abreviado que o Google atribui com base na região que você selecionou ao criar o aplicativo. O código não corresponde a um país ou estado, ainda que alguns IDs de região sejam semelhantes aos códigos de país e estado geralmente usados. Para aplicativos criados após fevereiro de 2020, o REGION_ID.r está incluído nos URLs do App Engine. Para apps existentes criados antes dessa data, o ID da região é opcional no URL.

Saiba mais sobre IDs de região.

Os aplicativos da Web em Java usam um arquivo descritor de implantação para determinar como os URLs são mapeados para servlets, quais URLs exigem autenticação e outras informações. Esse arquivo é chamado web.xml e fica armazenado no WAR do aplicativo no diretório WEB-INF/. web.xml faz parte da norma de servlet para aplicativos web.

Para mais informações sobre o padrão web.xml, consulte o wiki de referência do Metawerx sobre web.xml e a especificação do Servlet (ambos em inglês).

Descritores de implantação

O descritor de implantação de um aplicativo da Web indica as classes, os recursos e a configuração do aplicativo e como o servidor da Web os utiliza para veicular solicitações da Web. Ao receber uma solicitação do aplicativo, o servidor da Web usa o descritor de implantação a fim de mapear o URL da solicitação para o código que precisa processá-la.

O descritor de implantação é um arquivo chamado web.xml. Ele fica armazenado no WAR do aplicativo no diretório WEB-INF/. O arquivo é um arquivo XML cujo elemento raiz é <web-app>.

Veja a seguir um exemplo web.xml simples de que mapeia todos os caminhos de URL (/*) para a classe de servlet mysite.server.ComingSoonServlet:

<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>comingsoon</servlet-name>
        <servlet-class>mysite.server.ComingSoonServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>comingsoon</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Servlets e caminhos de URL

web.xml define os mapeamentos entre os caminhos de URL e os servlets que processarão as solicitações com esses caminhos. O servidor da Web usa essa configuração a fim de identificar o servlet para processar uma determinada solicitação e chamar o método da classe correspondente ao da solicitação. Por exemplo: o método doGet() para solicitações HTTP GET.

Para mapear um URL para um servlet, você precisa declarar o servlet com o elemento <servlet> e, em seguida, definir um mapeamento de um caminho de URL para uma declaração de servlet com o elemento <servlet-mapping>.

O elemento <servlet> declara o servlet, incluindo um nome usado para fazer o encaminhamento para o servlet por outros elementos no arquivo, a classe a ser usada para o servlet e os parâmetros de inicialização. Você pode declarar vários servlets usando a mesma classe com parâmetros diferentes de inicialização. O nome de cada servlet precisa ser exclusivo no descritor de implantação.

    <servlet>
        <servlet-name>redteam</servlet-name>
        <servlet-class>mysite.server.TeamServlet</servlet-class>
        <init-param>
            <param-name>teamColor</param-name>
            <param-value>red</param-value>
        </init-param>
        <init-param>
            <param-name>bgColor</param-name>
            <param-value>#CC0000</param-value>
        </init-param>
    </servlet>

    <servlet>
        <servlet-name>blueteam</servlet-name>
        <servlet-class>mysite.server.TeamServlet</servlet-class>
        <init-param>
            <param-name>teamColor</param-name>
            <param-value>blue</param-value>
        </init-param>
        <init-param>
            <param-name>bgColor</param-name>
            <param-value>#0000CC</param-value>
        </init-param>
    </servlet>

O elemento <servlet-mapping> especifica um padrão de URL e o nome de um servlet declarado a ser usado para solicitações cujo URL corresponde ao padrão. O padrão de URL pode usar um asterisco (*) no início ou no fim para indicar zero ou um número maior de determinado caractere. O padrão não é compatível com caracteres curinga no meio de uma string e não permite vários desses caracteres em um padrão. O padrão corresponde ao caminho completo do URL, começando com (e incluindo) a barra (/) seguida do nome de domínio. O caminho do URL não pode começar com um ponto final (.).

    <servlet-mapping>
        <servlet-name>redteam</servlet-name>
        <url-pattern>/red/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>blueteam</servlet-name>
        <url-pattern>/blue/*</url-pattern>
    </servlet-mapping>

Com este exemplo, uma solicitação para o URL http://www.example.com/blue/teamProfile é manipulada pela classe TeamServlet, com o parâmetro teamColor igual a blue e o parâmetro bgColor igual a #0000CC. O servlet pode obter a parte do caminho de URL correspondida pelo curinga usando o método getPathInfo() do objeto ServletRequest.

O servlet pode acessar seus parâmetros de inicialização obtendo sua configuração de servlet usando seu próprio método getServletConfig() e, em seguida, chamando o método getInitParameter() no objeto de configuração usando o nome do parâmetro como um argumento.

String teamColor = getServletConfig().getInitParameter("teamColor");

JSPs

Um app pode usar páginas do JavaServer (JSPs, na sigla em inglês) para implementar páginas da Web. JSPs são servlets definidos por meio do uso de conteúdo estático, como HTML, combinado ao código Java.

O App Engine é compatível com a compilação automática e o mapeamento de URLs para JSPs. Um arquivo JSP no WAR do aplicativo (fora de WEB-INF/) com um nome que termina em .jsp é compilado automaticamente em uma classe de servlet e mapeado para o caminho de URL equivalente ao caminho do arquivo JSP na raiz do WAR. Por exemplo, se um aplicativo tiver um arquivo JSP chamado start.jsp em um subdiretório chamado register/ de seu WAR, o App Engine o compilará e o mapeará para o caminho de URL /register/start.jsp.

Se você desejar ter mais controle sobre o mapeamento de JSP para um URL, pode especificar o mapeamento explicitamente declarando-o com um elemento <servlet> no descritor de implantação. Em vez de um elemento <servlet-class>, especifique um elemento <jsp-file> com o caminho do arquivo JSP na raiz do WAR. O elemento <servlet> da JSP pode conter parâmetros de inicialização.

    <servlet>
        <servlet-name>register</servlet-name>
        <jsp-file>/register/start.jsp</jsp-file>
    </servlet>

    <servlet-mapping>
        <servlet-name>register</servlet-name>
        <url-pattern>/register/*</url-pattern>
    </servlet-mapping>

É possível instalar as bibliotecas de tags da JSP com o elemento <taglib>. Uma biblioteca de tags tem um caminho para o arquivo TLD do JSP (<taglib-location>) e um URI usado pelas JSPs para selecionar a biblioteca para carregamento (<taglib-uri>). Observe que o App Engine fornece a biblioteca de tags padrão de páginas JavaServer (JSTL) e você não precisa instalá-la (link em inglês).

    <taglib>
        <taglib-uri>/escape</taglib-uri>
        <taglib-location>/WEB-INF/escape-tags.tld</taglib-location>
    </taglib>

Segurança e autenticação

Um aplicativo do App Engine pode usar as Contas do Google na autenticação do usuário. O app pode usar a Google Accounts API para detectar se o usuário fez login, conseguir o endereço de e-mail do usuário conectado no momento e gerar URLs de login e saída. Um app também pode especificar restrições de acesso a caminhos de URL com base nas Contas do Google, usando o descritor de implantação.

O elemento <security-constraint> define uma restrição de segurança para URLs que correspondem a determinado padrão. Se um usuário acessar um URL com um caminho que tenha uma restrição de segurança e não tiver feito login, o App Engine o redirecionará para a página de login das Contas do Google. As Contas do Google redirecionam o usuário para o URL do aplicativo depois que ele faz login ou após o registro de uma nova conta. O app não precisa fazer mais nada para garantir que somente usuários que fizeram login possam acessar o URL.

Uma restrição de segurança inclui uma restrição de autorização que especifica quais usuários das Contas do Google podem acessar o caminho. Se a restrição de autorização especificar uma função de usuário de *, todos os usuários que fizerem login com uma Conta do Google poderão acessar o URL. Se a restrição especificar um papel de usuário de admin, apenas os desenvolvedores registrados do aplicativo poderão acessar o URL. A função admin facilita a criação de seções do seu site exclusivas para os administradores.

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>profile</web-resource-name>
            <url-pattern>/profile/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>*</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>admin</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

O App Engine não oferece suporte a funções de segurança personalizadas (<security-role>) ou mecanismos de autenticação alternativos (<login-config>) no descritor de implementação.

As restrições de segurança se aplicam a arquivos estáticos e a servlets.

URLs seguros

O Google App Engine oferece suporte a conexões seguras através de HTTPS para URLs que usam o domínio REGION_ID.r.appspot.com. Quando uma solicitação acessa um URL que usa HTTPS e esse URL está configurado para usar HTTPS no arquivo web.xml, tanto os dados de solicitação como os dados de resposta são criptografados pelo remetente antes de serem transmitidos e descriptografados pelo destinatário quando recebidos. As conexões seguras são úteis para proteger dados de clientes, como informações de contato, senhas e mensagens particulares.

Para declarar que o HTTPS precisa ser usado para um URL, configure uma restrição de segurança no descritor de implantação (conforme descrito em Segurança e autenticação) com um <user-data-constraint> em que o <transport-guarantee> seja CONFIDENTIAL. Exemplo:

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>profile</web-resource-name>
            <url-pattern>/profile/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

As solicitações que usam HTTP (não seguro) em URLs com garantia de transporte como CONFIDENTIAL são redirecionadas automaticamente para o mesmo URL que usa HTTPS.

Qualquer URL pode usar a garantia de transporte CONFIDENTIAL, inclusive JSPs e arquivos estáticos.

O servidor da Web de desenvolvimento não é compatível com conexões HTTPS. Ele ignora a garantia de transporte. Dessa maneira, os caminhos a serem usados com HTTPS podem ser testados usando conexões HTTP regulares com o servidor da Web de desenvolvimento.

Quando você testa os manipuladores HTTPS de seu aplicativo usando o URL appspot.com ao qual foi atribuída a versão, como https://1.latest.your_app_id.REGION_ID.r.appspot.com/, seu navegador exibe um aviso informando que o certificado HTTPS não foi assinado para esse caminho de domínio específico. Se aceitar o certificado desse domínio, as páginas serão carregadas com êxito. Os usuários não verão o aviso do certificado quando acessarem https://your_app_id.REGION_ID.r.appspot.com/.

Também é possível usar uma forma alternativa do URL appspot.com desenvolvido para evitar esse problema substituindo os pontos que separam os componentes do subdomínio pela string "-dot-". Por exemplo, o exemplo anterior pode ser acessado sem um aviso de certificado em https://VERSION_ID-dot-default-dot-PROJECT_ID.REGION_ID.r.appspot.com.

O login e a saída das Contas do Google são sempre realizados usando uma conexão segura, e isso não está relacionado à maneira como os URLs do aplicativo estão configurados.

Conforme mencionado acima, as restrições de segurança se aplicam a arquivos estáticos e a servlets. Isso inclui a garantia de transporte.

Observação: o Google recomenda (em inglês) o uso do protocolo HTTPS para enviar solicitações ao seu aplicativo. O Google não emite certificados SSL para domínios com caracteres curinga duplos hospedados em appspot.com. Por isso, com HTTPS, você precisa usar a string "-dot-", em vez de ".", para separar subdomínios, conforme demonstrado nos exemplos abaixo. É possível usar um "." simples com seu próprio domínio personalizado ou com endereços HTTP.

Lista de arquivos de boas-vindas

Quando os URLs do site representam caminhos para arquivos estáticos ou JSPs no WAR, costuma ser bom também ter caminhos para diretórios fazendo algo útil. Um usuário que visita o caminho do URL /help/accounts/password.jsp para conseguir informações sobre senhas de contas pode tentar visitar /help/accounts/ para encontrar uma página que introduza a documentação do sistema de contas. O descritor de implantação pode especificar uma lista de nomes de arquivo que o servidor precisa tentar quando o usuário acessa um caminho que representa um subdiretório do WAR ainda não mapeado explicitamente para um servlet. O padrão do servlet chama isso de "lista de arquivos de boas-vindas".

Por exemplo, se usuário acessar o caminho de URL /help/accounts/, o seguinte elemento <welcome-file-list> no descritor de implantação solicitará que o servidor procure help/accounts/index.jsp e help/accounts/index.html antes de comunicar que o URL não existe:

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

Filtros

Um filtro é uma classe que atua em uma solicitação, como um servlet, mas que pode permitir que o processamento da solicitação continue com outros filtros ou servlets. Um filtro pode realizar uma tarefa auxiliar, como geração de registros, realização de verificações especializadas de autenticação ou anotação dos objetos de solicitação ou de resposta, antes de chamar o servlet. Os filtros permitem escrever tarefas de processamento de solicitação no descritor de implantação.

Uma classe de filtro implementa a interface javax.servlet.Filter, incluindo o método doFilter(). Veja a seguir uma implementação de filtro simples que registra uma mensagem e passa o controle pela cadeia, que pode incluir outros filtros ou um servlet, conforme indicado pelo descritor de implantação:

package mysite.server;

import java.io.IOException;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class LogFilterImpl implements Filter {

    private FilterConfig filterConfig;
    private static final Logger log = Logger.getLogger(LogFilterImpl.class.getName());

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws IOException, ServletException {
        log.warning("Log filter processed a " + getFilterConfig().getInitParameter("logType")
            + " request");

        filterChain.doFilter(request, response);
    }

    public FilterConfig getFilterConfig() {
        return filterConfig;
    }

    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }

    public void destroy() {}

}

Assim como os servlets, você pode configurar um filtro no descritor de implantação declarando-o com o elemento <filter> e, em seguida, mapeando-o para um padrão de URL com o elemento <filter-mapping>. Também é possível mapear filtros diretamente para outros servlets.

O elemento <filter> contém um <filter-name>, <filter-class> e elementos <init-param> opcionais.

    <filter>
        <filter-name>logSpecial</filter-name>
        <filter-class>mysite.server.LogFilterImpl</filter-class>
        <init-param>
            <param-name>logType</param-name>
            <param-value>special</param-value>
        </init-param>
    </filter>

O elemento <filter-mapping> contém um <filter-name>, que corresponde ao nome de um filtro declarado e um elemento <url-pattern>, para aplicar o filtro aos URLs, ou um elemento <servlet-name>, que corresponde ao nome de um servlet declarado para aplicar o filtro sempre que o servlet for chamado.

    <!-- Log for all URLs ending in ".special" -->
    <filter-mapping>
        <filter-name>logSpecial</filter-name>
        <url-pattern>*.special</url-pattern>
    </filter-mapping>

    <!-- Log for all URLs that use the "comingsoon" servlet -->
    <filter-mapping>
        <filter-name>logSpecial</filter-name>
        <servlet-name>comingsoon</servlet-name>
    </filter-mapping>

Gerenciadores de erros

Com o descritor de implantação, você pode personalizar o que o servidor envia ao usuário quando ocorre um erro. O servidor poderá exibir um local alternativo de página quando estiver prestes a enviar um determinado código de status HTTP ou quando um servlet gerar uma determinada exceção Java.

O elemento <error-page> contém um elemento <error-code> com um valor de código de erro HTTP (como 500) ou um <exception-type> com o nome da classe da exceção esperada (como java.io.IOException). Ele também contém um <location> que contém o caminho do URL do recurso a ser exibido quando o erro ocorre.

    <error-page>
        <error-code>500</error-code>
        <location>/errors/servererror.jsp</location>
    </error-page>

Recursos incompatíveis do web.xml

Os recursos do web.xml a seguir não são compatíveis com o App Engine:

  • O App Engine oferece suporte ao elemento <load-on-startup> para declarações de servlet. No entanto, o carregamento ocorre efetivamente durante a primeira solicitação processada pela instância do servidor da Web, e não antes dela.
  • Alguns elementos do descritor de implantação aceitam um nome de exibição legível, uma descrição e um ícone a serem usados em ambientes de desenvolvimento integrado. O App Engine não os utiliza e os ignora.
  • O App Engine não oferece suporte a variáveis de ambiente JNDI (<env-entry>).
  • O App Engine não oferece suporte a recursos EJB (<resource-ref>).
  • Não são aceitos filtros, notificações de destruição de servlets e contexto do servlets.
  • O elemento <distributable> é ignorado.
  • Não há suporte à programação do servlet com <run-at>.