2010-03-24 9 views
5

Avevo recentemente un problema con la codifica dei siti Web generati da servlet, che si verificava se i servlet venivano distribuiti sotto Tomcat, ma non sotto Jetty. Ho fatto un po 'di ricerca su di esso e semplificato il problema al seguente servlet:Perché la codifica non è impostata in risposta da Tomcat? Come posso affrontarlo?

public class TestServlet extends HttpServlet implements Servlet { 
    @Override 
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { 
     response.setContentType("text/plain"); 
     Writer output = response.getWriter(); 
     output.write("öäüÖÄÜß"); 
     output.flush(); 
     output.close(); 
    } 
} 

Se schiero questo sotto Jetty e indirizzare il browser per esso, restituisce il risultato atteso. I dati vengono restituiti come ISO-8859-1 e se prendo uno sguardo nelle intestazioni, quindi Jetty ritorna:

Content-Type: text/plain; charset=iso-8859-1 

Il browser rileva la codifica da questa intestazione. Se distribuisco lo stesso servlet in Tomcat, il browser mostra caratteri strani. Ma Tomcat restituisce anche i dati come ISO-8859-1, la differenza è che nessuna intestazione ne parla. Quindi il browser deve indovinare la codifica, e questo va storto.

La mia domanda è: il comportamento di Tomcat è corretto o un bug? E se è corretto, come posso evitare questo problema? Certo, posso sempre aggiungere response.setCharacterEncoding("UTF-8"); al servlet, ma ciò significa che ho impostato una codifica fissa, che il browser potrebbe o potrebbe non capire. Il problema è più rilevante, se nessun browser, ma un altro servizio accede al servlet. Quindi, come dovrei affrontare il problema nel modo più flessibile?

+0

Btw: 'implementa Servlet' è superfluo come' HttpServlet' fa già questo. – BalusC

risposta

-1

Se non si specifica la codifica, Tomcat è libero di codificare i propri personaggi come si sente, e il browser è libero di indovinare quale codifica ha scelto Tomcat. Hai ragione nel senso che il modo per risolvere il problema è response.setCharacterEncoding("UTF-8").

Non dovresti preoccuparti della possibilità che il browser non capisca la codifica, poiché praticamente tutti i browser rilasciati negli ultimi 10 anni supportano UTF-8. Anche se sei davvero preoccupato, puoi controllare le intestazioni "Accetta-Codifica" fornite dall'agente utente.

+1

Non è corretto, la specifica richiede ISO-8859-1 come codifica predefinita. –

+0

Non ho alcun problema con tomcat che seleziona una codifica, ma un problema con il fatto che tomcat non dice al browser quale codifica stava scegliendo. E come ho scritto, i browser moderni possono supportare codifiche ISO e Unicode, ma altri programmi possono accedere ai servizi forniti dai servlet. – Dishayloo

+0

@Tim: Quale specifica sarebbe? Direi che probabilmente è irrilevante in questo caso. –

4

Se non si specifica una codifica, la specifica Servlet richiede ISO-8859-1. Tuttavia, AFAIK non richiede che il contenitore imposti la codifica nel tipo di contenuto, almeno non se lo si imposta su "text/plain". Così dice la specifica:

chiamate verso setContentType impostare la codifica dei caratteri solo se il dato tipo di contenuto corda fornisce un valore per l'attributo charset.

In altre parole, solo se si imposta il tipo di contenuto come questo

response.setContentType("text/plain; charset=XXXX") 

Tomcat è necessario per impostare il set di caratteri. Non ho ancora provato se questo funziona.

In generale, consiglierei di impostare sempre la codifica su UTF-8 (in quanto provoca il minor numero di problemi, almeno nei browser) e quindi, per testo/semplice, indicare esplicitamente la codifica, per evitare i browser dall'utilizzo di un default di sistema.

+0

Hmm, il comportamento del Jetty è errato? Il molo rende le cose molto più semplici in questo caso, poiché funziona come previsto. – Dishayloo

+0

Penso di sì. O almeno non riesco a trovare nulla nelle specifiche che dicono che Jetty dovrebbe modificare il tipo di contenuto in questo caso. –

0

Ecco un filtro che ho scritto forzare UTF-8 codifica:

public class CharacterEncodingFilter implements Filter { 
private static final Logger log = Logger.getLogger(CharacterEncodingFilter.class.getName()); 

boolean isConnectorConfigured = false; 

public void init(FilterConfig filterConfig) throws ServletException {} 

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
    request.setCharacterEncoding("utf-8"); 
    response.setCharacterEncoding("utf-8"); 
    if(! isConnectorConfigured) { 
     isConnectorConfigured = true; 
     try { //I need to do all of this with reflection, because I get NoClassDefErrors otherwise. --jsb 
      Field f = request.getClass().getDeclaredField("request"); //Tomcat wraps the real request in a facade, need to get it 
      f.setAccessible(true); 
      Object req = f.get(request); 
      Object connector = req.getClass().getMethod("getConnector", new Class[0]).invoke(req); //Now get the connector 
      connector.getClass().getMethod("setUseBodyEncodingForURI", new Class[] {boolean.class}).invoke(connector, Boolean.TRUE); 
     } catch(NoSuchFieldException e) { 
      log.log(Level.WARNING, "Servlet container does not seem to be Tomcat, cannot programatically alter character encoding. Do this in the Server.xml <Connector> attribute instead."); 
     } catch(Exception e) { 
      log.log(Level.WARNING, "Could not setUseBodyEncodingForURI to true on connector"); 
     } 
    } 
    chain.doFilter(request, response); 
} 

public void destroy() {} 

}

2

A sostegno della risposta di Jesse Barnum, l'apache Wiki suggerisce che un filtro può essere utilizzato per controllare il carattere codifica della richiesta e della risposta. Tuttavia, Tomcat 5.Le versioni 5 e successive vengono fornite in bundle con SetCharacterEncodingFilter, quindi potrebbe essere preferibile utilizzare l'implementazione di apache piuttosto che utilizzare Jesse (senza offesa Jesse). Le implementazioni di tomcat impostano solo la codifica dei caratteri sulla richiesta, pertanto potrebbe essere necessario modificare il filtro per impostare il set di caratteri sulla risposta di tutti i servlet.

particolare, Tomcat ha implementazioni esempi qui:

5.x

webapps/servlet-examples/WEB-INF/classes/filtri/SetCharacterEncodingFilter.java

webapps/jsp- esempi/WEB-INF/classes/filtri/SetCharacterEncodingFilter.java

6.x

webapps/examples/WEB-INF/classes/filtri/SetCharacterEncodingFilter.java

7.x

Poiché 7.0.20 filtro divenne cittadino di prima classe è stato spostato e dagli esempi in Tomcat nucleo ed è disponibile a qualsiasi applicazione Web senza la necessità di compilarlo e raggrupparlo separatamente. Vedi la documentazione per l'elenco dei filtri forniti da Tomcat. Il nome della classe è: org.apache.catalina.filters.SetCharacterEncodingFilter

Questa pagina dice di più: http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q3

Problemi correlati