Il descrittore di deployment: web.xml

ID regione

L'REGION_ID è un codice abbreviato che Google assegna in base alla regione selezionata quando crei l'app. Il codice non corrisponde a un paese o a una provincia, anche se alcuni ID regione possono sembrare simili ai codici di paesi e province di uso comune. Per le app create dopo febbraio 2020, REGION_ID.r è incluso negli URL di App Engine. Per le app esistenti create prima di questa data, l' ID regione è facoltativo nell'URL.

Scopri di più sugli ID regione.

Le applicazioni web Java utilizzano un file descrittore di deployment per determinare in che modo gli URL vengono mappati ai servlet, quali URL richiedono l'autenticazione e altre informazioni. Questo file si chiama web.xml e fa parte della specifica servlet per le applicazioni web. Per saperne di più sul descrittore di deployment web.xml, consulta la specifica servlet.

Se esegui la migrazione da Java 8 e devi utilizzare i servizi in bundle precedenti con l'ultima versione di Java supportata, devi aggiungere l' <app-engine-apis> elemento e impostarlo su true nel file web.xml:

<app-engine-apis>true</app-engine-apis>

Descrittori di deployment

Il descrittore di deployment di un'applicazione web descrive le classi, le risorse e la configurazione dell'applicazione e il modo in cui il server web le utilizza per gestire le richieste web. Quando il server web riceve una richiesta per l'applicazione, utilizza il descrittore di deployment per mappare l'URL della richiesta al codice che deve gestirla.

Il descrittore di deployment è un file denominato web.xml. Si trova nel file WAR dell'app nella directory WEB-INF/. Il file è un file XML il cui elemento principale è <web-app>.

Il seguente esempio di web.xml mappa tutti i percorsi URL (/*) alla classe servlet mysite.server.ComingSoonServlet per Jakarta EE 10, EE 11 su servlet 6.0 e Java EE 8. Per utilizzare l'ultima versione supportata nella configurazione predefinita, devi aggiornare i servlet e le dipendenze dell'applicazione in modo da includere lo spazio dei nomi Jakarta. Per scoprire di più sulle opzioni di configurazione, consulta Eseguire l'upgrade di un'applicazione esistente.

Jakarta EE 11

<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_1.xsd"
     version="6.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>

Jakarta EE 10

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

Java EE 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">
    <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>

Se fattorizzi l'applicazione in servizi, ogni servizio ha i propri parametri di configurazione.

Servlet e percorsi URL

web.xml definisce i mapping tra i percorsi URL e i servlet che gestiscono le richieste con questi percorsi. Il server web utilizza questa configurazione per identificare il servlet che deve gestire una determinata richiesta e chiamare il metodo della classe corrispondente al metodo della richiesta. Ad esempio, il metodo doGet() per le richieste HTTP GET.

Per mappare un URL a un servlet, devi dichiarare il servlet con l'elemento <servlet>, quindi definire una mappatura da un percorso dell'URL a una dichiarazione servlet con l'elemento <servlet-mapping>.

L'elemento <servlet> dichiara il servlet, incluso un nome utilizzato per fare riferimento a il servlet da altri elementi del file, la classe da utilizzare per il servlet e i parametri di inizializzazione. Puoi dichiarare più servlet utilizzando la stessa classe con parametri di inizializzazione diversi. Il nome di ogni servlet deve essere univoco nel descrittore di deployment.

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

L'elemento <servlet-mapping> specifica un pattern URL e il nome di un servlet dichiarato da utilizzare per le richieste il cui URL corrisponde al pattern. Il pattern URL può utilizzare un asterisco (*) all'inizio o alla fine del pattern per indicare zero o più caratteri. Il pattern URL non supporta i caratteri jolly al centro di una stringa e non consente più caratteri jolly in un pattern. Il pattern corrisponde al percorso completo dell'URL, a partire dalla barra (/) dopo il nome di dominio e includendola. Il percorso dell'URL non può iniziare con un punto (.).

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

Con questo esempio, una richiesta per l'URL http://www.example.com/blue/teamProfile viene gestita dalla classe TeamServlet, con il parametro teamColor uguale a blue e il parametro bgColor uguale a #0000CC. Il servlet può ottenere la parte del percorso URL corrispondente al carattere jolly utilizzando il metodo getPathInfo() dell'oggetto ServletRequest.

Il servlet può accedere ai parametri di inizializzazione ottenendo la configurazione del servlet utilizzando il proprio metodo getServletConfig(), quindi chiamando il metodo getInitParameter() sull'oggetto di configurazione utilizzando il nome del parametro come argomento.

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

JSP

Un'app può utilizzare le JavaServer Pages (JSP) per implementare le pagine web. Le JSP sono servlet definite utilizzando contenuti statici, come HTML, combinati con codice Java.

App Engine supporta la compilazione automatica e il mapping degli URL per le JSP. Un file JSP nel file WAR dell'applicazione (al di fuori di WEB-INF/) il cui nome file termina con .jsp viene compilato automaticamente in una classe servlet e mappato al percorso dell'URL equivalente al percorso del file JSP dalla radice WAR. Ad esempio, se un'app ha un file JSP denominato start.jsp in una sottodirectory denominata register/ nel file WAR, App Engine lo compila e lo mappa al percorso dell'URL /register/start.jsp.

Se vuoi avere un maggiore controllo sulla mappatura della JSP a un URL, puoi specificare il mapping in modo esplicito dichiarandolo con un elemento <servlet> nel descrittore di deployment. Anziché un elemento <servlet-class>, devi specificare un elemento <jsp-file> con il percorso del file JSP dalla radice WAR. L'elemento <servlet> per la JSP può contenere parametri di inizializzazione.

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

Puoi installare le librerie di tag JSP con l'elemento <taglib>. Una libreria di tag ha un percorso del file descrittore della libreria di tag JSP (TLD) (<taglib-location>) e un URI che le JSP utilizzano per selezionare la libreria da caricare (<taglib-uri>). Tieni presente che App Engine fornisce la JavaServer Pages Standard Tag Library (JSTL) e non devi installarla.

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

Sicurezza e autenticazione

Un'applicazione App Engine può utilizzare gli Account Google per l'autenticazione degli utenti. L' app può utilizzare l'API Account Google per rilevare se l'utente ha eseguito l'accesso, ottenere l'indirizzo email dell'utente che ha eseguito l'accesso e generare URL di accesso e disconnessione. Un'app può anche specificare le limitazioni di accesso per i percorsi URL in base agli Account Google, utilizzando il descrittore di deployment.

L'elemento <security-constraint> definisce una limitazione di sicurezza per gli URL che corrispondono a un pattern. Se un utente accede a un URL il cui percorso ha una limitazione di sicurezza e l'utente non ha eseguito l'accesso, App Engine lo reindirizza alla pagina di accesso degli Account Google. Gli Account Google reindirizzano l'utente all'URL dell'applicazione dopo aver eseguito l'accesso o registrato un nuovo account. L'app non deve fare altro per garantire che solo gli utenti che hanno eseguito l'accesso possano accedere all'URL.

Una limitazione di sicurezza include una limitazione di autorizzazione che specifica a quali utenti degli Account Google è consentito accedere al percorso. Se la limitazione di autorizzazione specifica un ruolo utente *, qualsiasi utente che ha eseguito l'accesso con un Account Google può accedere all'URL. Se la limitazione specifica un ruolo utente admin, solo gli sviluppatori registrati dell'applicazione possono accedere all'URL. Il ruolo admin semplifica la creazione di sezioni del sito riservate agli amministratori.

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

App Engine non supporta i ruoli di sicurezza personalizzati (<security-role>) o i meccanismi di autenticazione alternativi (<login-config>) nel descrittore di deployment.

Le limitazioni di sicurezza si applicano sia ai file statici sia ai servlet.

URL sicuri

App Engine supporta le connessioni sicure con HTTPS per gli URL che utilizzano il REGION_ID.r.appspot.com dominio. Quando una richiesta accede a un URL utilizzando HTTPS e l'URL è configurato per utilizzare HTTPS nel file web.xml, sia i dati della richiesta sia i dati della risposta vengono criptati dal mittente prima della trasmissione e decriptati dal destinatario dopo la ricezione. Le connessioni sicure sono utili per proteggere i dati dei clienti, come informazioni di contatto, password e messaggi privati.

Per dichiarare che HTTPS deve essere utilizzato per un URL, devi configurare una limitazione di sicurezza nel descrittore di deployment (come descritto in Sicurezza e autenticazione) con un <user-data-constraint> il cui <transport-guarantee> è CONFIDENTIAL. Ad esempio:

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

Le richieste che utilizzano HTTP (non sicuro) per gli URL la cui garanzia di trasporto è CONFIDENTIAL vengono reindirizzate automaticamente allo stesso URL utilizzando HTTPS.

Qualsiasi URL può utilizzare la garanzia di trasporto CONFIDENTIAL, inclusi JSP e file statici.

Il server web di sviluppo non supporta le connessioni HTTPS. Ignora la garanzia di trasporto, quindi i percorsi destinati all'uso con HTTPS possono essere testati utilizzando le normali connessioni HTTP al server web di sviluppo.

Quando testi i gestori HTTPS della tua app utilizzando l'URL appspot.com con versione, ad esempio https://1.latest.your_app_id.REGION_ID.r.appspot.com/, il browser ti avvisa che il certificato HTTPS non è stato firmato per quel percorso di dominio specifico. Se accetti il certificato per quel dominio, le pagine verranno caricate correttamente. Gli utenti non vedranno l'avviso del certificato quando accedono a https://your_app_id.REGION_ID.r.appspot.com/.

Puoi anche utilizzare una forma alternativa dell'URL appspot.com con versione progettata per evitare questo problema sostituendo i punti che separano i componenti del sottodominio con la stringa "-dot-". Ad esempio, l'esempio precedente potrebbe essere accessibile senza un avviso di certificato all'indirizzo https://VERSION_ID-dot-default-dot-PROJECT_ID.REGION_ID.r.appspot.com.

L'accesso e la disconnessione degli Account Google vengono sempre eseguiti utilizzando una connessione sicura e non sono correlati alla configurazione degli URL dell'applicazione.

Come indicato in precedenza, le limitazioni di sicurezza si applicano sia ai file statici sia ai servlet. Ciò include la garanzia di trasporto.

Nota: Google consiglia di utilizzare il protocollo HTTPS per inviare richieste alla tua app. Google non rilascia certificati SSL per i domini con doppio carattere jolly ospitati su appspot.com. Pertanto, con HTTPS devi utilizzare la stringa "-dot-" anziché "." per separare i sottodomini, come mostrato negli esempi riportati di seguito. Puoi utilizzare un semplice "." con il tuo dominio personalizzato o con gli indirizzi HTTP.

L'elenco dei file di benvenuto

Quando gli URL del tuo sito rappresentano i percorsi dei file statici o delle JSP nel file WAR, spesso è una buona idea che i percorsi delle directory facciano anche qualcosa di utile. Un utente che visita il percorso dell'URL /help/accounts/password.jsp per informazioni sulle password dell'account potrebbe provare a visitare /help/accounts/ per trovare una pagina che introduce la documentazione del sistema di account. Il descrittore di deployment può specificare un elenco di nomi file che il server deve provare quando l'utente accede a un percorso che rappresenta una sottodirectory WAR che non è già mappata in modo esplicito a un servlet. La specifica servlet la chiama welcome file list.

Ad esempio, se l'utente accede al percorso dell'URL /help/accounts/, il seguente <welcome-file-list> elemento nel descrittore di deployment indica al server di controllare help/accounts/index.jsp e help/accounts/index.html prima di segnalare che l'URL non esiste:

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

Filtri

Un filtro è una classe che agisce su una richiesta come un servlet, ma può consentire la gestione della richiesta con altri filtri o servlet. Un filtro può eseguire un'attività ausiliaria, come la registrazione, l'esecuzione di controlli di autenticazione specializzati o l'annotazione degli oggetti di richiesta o risposta prima di chiamare il servlet. I filtri consentono di comporre le attività di elaborazione delle richieste dal descrittore di deployment.

Il seguente esempio di implementazione del filtro registra un messaggio e passa il controllo alla catena, che può includere altri filtri o un servlet, come descritto dal descrittore di deployment per la versione 21 e successive su EE10 (impostazione predefinita), la versione 21 su EE8 e la versione 17 e precedenti. Per utilizzare l'ultima versione supportata nella configurazione predefinita, devi aggiornare i servlet e le dipendenze dell'applicazione in modo da includere lo spazio dei nomi Jakarta. Per scoprire di più sulle opzioni di configurazione, consulta Eseguire l'upgrade di un'applicazione esistente.

v21 e versioni successive (EE10)

Questa classe di filtri implementa l'interfaccia jakarta.servlet.Filter con il metodo doFilter().

package mysite.server;

import java.io.IOException;
import java.util.logging.Logger;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.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() {}

}

v21 (EE8)

Questa classe di filtri implementa l'interfaccia javax.servlet.Filter con il metodo doFilter().

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() {}

}

v17 e versioni precedenti

Questa classe di filtri implementa l'interfaccia javax.servlet.Filter con il metodo doFilter().

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() {}

}

Analogamente ai servlet, devi configurare un filtro nel descrittore di deployment dichiarando il filtro con l'elemento <filter>, quindi mappandolo a un pattern URL con l'elemento <filter-mapping>. Puoi anche mappare i filtri direttamente ad altri servlet.

L'elemento <filter> contiene gli elementi <filter-name>, <filter-class> e <init-param> facoltativi.

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

L'elemento <filter-mapping> contiene un <filter-name> che corrisponde al nome di un filtro dichiarato e un elemento <url-pattern> per applicare il filtro agli URL o un elemento <servlet-name> che corrisponde al nome di un servlet dichiarato per applicare il filtro ogni volta che viene chiamato il servlet.

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

Gestione degli errori

Puoi personalizzare ciò che il server invia all'utente quando si verifica un errore utilizzando il descrittore di deployment. Il server può visualizzare un percorso di pagina alternativo quando sta per inviare un determinato codice di stato HTTP o quando un servlet genera una determinata eccezione Java.

L'elemento <error-page> contiene un elemento <error-code> con un valore di codice di errore HTTP (ad esempio 500) o un elemento <exception-type> con il nome della classe dell'eccezione prevista (ad esempio java.io.IOException). Contiene anche un elemento <location> contenente il percorso dell'URL della risorsa da mostrare quando si verifica l'errore.

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

Non puoi configurare gestori di errori personalizzati per le seguenti condizioni di errore:

  • Pagina di risposta 404 quando non è definito alcun mapping di servlet per un URL.
  • Pagina di errore di quota 403
  • Pagina di errore del server 500 che viene visualizzata dopo un errore interno di App Engine.

Funzionalità web.xml non supportate

Le seguenti funzionalità web.xml non sono supportate da App Engine:

  • App Engine supporta l'elemento <load-on-startup> per le dichiarazioni di servlet. Tuttavia, il caricamento avviene durante la prima richiesta gestita dall'istanza del server web, non prima.
  • Alcuni elementi del descrittore di deployment possono accettare un nome visualizzato, una descrizione e un'icona leggibili per l'utilizzo negli IDE. App Engine non li utilizza e li ignora.
  • App Engine non supporta le variabili di ambiente JNDI (<env-entry>).
  • App Engine non supporta le risorse EJB (<resource-ref>).
  • La notifica della distruzione di servlet, contesto servlet o filtri non è supportata.
  • L'elemento <distributable> viene ignorato.
  • La pianificazione dei servlet con <run-at> non è supportata.