Ich möchte verschiedene Sprachen und Sonderzeichendurch mein
Servlet verarbeiten.
Das Servlet gibt UTF-8 aus und nimmt im Request UTF-8 entgegen.
Mit
lastname = request.getParameter("lastname");
lastname = new String(lastname.getBytes(), "UTF-8");
gehen die kleinen Unmlaute oe ue ae wunderbar, doch nicht die grossen
und auch kein sz.
Die grossen Umlaute ÖÄÜ und ß werden in UTF-8 jeweils zu "Ã?"
Also immer zu dem selben Zeichen.
Es ist egal ob ich für den Request Mozilla oder den IE benutze.
Kann mir jemand helfen?
Robert Reitz wrote:
> Mit
> lastname = request.getParameter("lastname");
> lastname = new String(lastname.getBytes(), "UTF-8");
> gehen die kleinen Unmlaute oe ue ae wunderbar, doch nicht die grossen
> und auch kein sz.
Da kann eigentlich nix Sinnvolles bei rauskommen. Nach der ersten
Zeile ist ja schon alles gegessen: Die Bytes der Requestparameter
wurden als Characterdaten interpretiert und in einen String gepackt.
In der zweiten Zeile liest Du den String als Bytes im Default-Encoding
des Servers aus und interpretierst sie dann, als waeren sie UTF-8-encoded.
Ich haette eigentlich vermutet, dass getParameter() schon immer das
richtige Ergebnis liefert. GET-Parameter lassen ueberhaupt keinen
Interpretationsspielraum beim Zeichensatz, exotische Zeichen muessen
gesondert codiert werden. POST-Parameter stehen im Body des Requests
und sollten daher gemaess dem im Header angegebenen Encoding
interpretiert werden.
Kann es sein, dass Du schon die richtigen Strings erhaeltst und sie
mit Deiner 'Umkodierung' nur verschlimmbesserst, dass Du GET-Parameter
nicht URL-encodest oder dass Du bei POST-Parametern nicht den
richtigen Zeichensatz angibst - IOW, dass das Problem nicht vorhanden
ist oder beim Client liegt?
Viele Gruesse,
Patrick
> Das Servlet gibt UTF-8 aus und nimmt im Request UTF-8 entgegen.
>
> lastname = request.getParameter("lastname");
> lastname = new String(lastname.getBytes(), "UTF-8");
> Kann mir jemand helfen?
Hallo Robert,
probier doch mal folgendes:
lastname = new String(request.getParameter("lastname").getBytes(), "UTF-8");
evtl. musst Du noch klammern, aber so sollte es funzen...
greets
Robert
--
Diese Mail wurde von einem freilaufenden, artgerecht gehaltenen Pinguin
erstellt und ist zu 100 Prozent Viren frei!
http://r-meyer.homelinux.com
Robert Meyer wrote:
>> lastname = request.getParameter("lastname");
>> lastname = new String(lastname.getBytes(), "UTF-8");
>> Kann mir jemand helfen?
[...]
> probier doch mal folgendes:
>
> lastname = new String(request.getParameter("lastname").getBytes(), "UTF-8");
>
> evtl. musst Du noch klammern, aber so sollte es funzen...
Sicher. Noch besser funzt es, wenn man sich dabei dreimal um die
eigene Achse dreht, dann die Hacken zusammenschlaegt und 'There's no
encoding like UTF-8' sagt. Und man muss das tote Huhn natuerlich
linksrum ueber den Monitor schwenken.
Nochmal: Die Interpretation nach einem Zeichensatz geschieht bereits
in getParameter(). Den dann bereits interpretierten String nach einem
Zeichensatz aus- und einem anderen wieder einzulesen ist hoeherer
Bloedsinn. Und welche magischen Kraefte man sich vom simplen Inlining
eines getParameter()-Aufrufs versprechen sollte, ist mir herzlich unklar.
Ich habe gerade mal kurz in den Tomcat-Source geschaut, und was ich da
sehe, bestaetigt meine Vermutungen, abgesehen davon, dass natuerlich
auch GET-Parameter gemaess dem im Header angegebenen Zeichensatz (oder
per Default als Latin-1) interpretiert werden - URL-Encoding deckt
schliesslich auch nur 8-Bit-Zeichen ab.
Viele Gruesse,
Patrick
ohne mich jetzt übermässig gut mit Servlets auszukennen, aber eines
erkenne ich hier schon... nä,lich dass deine "Lösung" das selbe ist wie
das von Robert Meyer. Der einzige Unerschied ist der, dass das bei dir
in einer Zeile geschrieben wird.
Ich denke Patrick ist da schon eher auf dem rechtem Weg.
Gruss theo
Bahhhhhh..., BRÜLL, cooler Anfang für heute :)
> Ich möchte verschiedene Sprachen und Sonderzeichendurch mein
> Servlet verarbeiten.
>
> Das Servlet gibt UTF-8 aus und nimmt im Request UTF-8 entgegen.
>
> Mit
> lastname = request.getParameter("lastname");
> lastname = new String(lastname.getBytes(), "UTF-8");
Im Prinzip richtig. auf welchem Betriebssystem arbeitest du?
'Mein' Tomcat (3.x) verwendete als encoding "ISO-8859-1",
das musst du Rückgängig machen, mit .getBytes() nimmst du
das default Encoding für deine Plattform. Versuch mal:
para = request.getParameter("lastname");
para = new String(para.getBytes("ISO-8859-1"), "UTF-8");
Sowas hatte ich auch mal, hier steht eine Lösung:
<http://groups.google.com/groups?ie=UTF-8&oe=UTF-8&as_umsgid=ak0vs0%241ej4o6%2...@ID-101012.news.dfncis.de&lr=&hl=de>
msgid= <ak0vs0$1ej4o6$1...@ID-101012.news.dfncis.de>
In der Folgenachricht auch ein Hinweis auf eine andere Lösung mit mordernerem Tomcat.
> gehen die kleinen Unmlaute oe ue ae wunderbar, doch nicht die grossen
> und auch kein sz.
> Die grossen Umlaute ÖÄÜ und ß werden in UTF-8 jeweils zu "Ã?"
Allerdings:
Beim mir gingen auch die kleinen Umlaute zuerst nicht, der Unterschied könnte
davon kommen das dein defaultencoding nur ähnlich wie iso-8859-1 ist.
> Also immer zu dem selben Zeichen.
Das sieht nur so aus, im String sind alle Daten vorhanden, nur bei der Ausgabe
werden sie bei unpassendem Encoding in das '?' umgewandelt.
Peter
sorry, Ihr habt ja recht - vermute ich hab da dann doch noch
geschlafen... lol
Werde das nächste mal wieder vorher mein Hirn einschalten - versprochen
Hätte ich noch schreiben sollen:
request.setCharacterEncoding("UTF-8");
vor request.getParameter(...)
Wenn ich einfach nur den Parameter lese und ohne Angabe von
setCharacterEncoding mit System.out ausgebe
kommt fuer ö ä ü Ö Ä Ü folgendes raus:
ö ä ü � � �
Mit request.setCharacterEncoding("UTF-8"); und
new String(request.getParameter("lastname").getBytes(), "UTF-8");
gibts entsprechend:
ö ä ü Ã? Ã? Ã?
Jedes deutsche Umlaut kommt vom IE als UTF-8 rein, da jeweils
2 Bytes ankommen. Das Problem ist nur dass bei grossen Umlauten
immer die selben 2 Bytes ankommen.
Robert
Robert Reitz wrote:
> request.setCharacterEncoding("UTF-8");
>
> vor request.getParameter(...)
>
> Wenn ich einfach nur den Parameter lese und ohne Angabe von
> setCharacterEncoding mit System.out ausgebe
> kommt fuer ö ä ü Ö Ä Ü folgendes raus:
>
> ö ä ü � � �
>
> Mit request.setCharacterEncoding("UTF-8"); und
> new String(request.getParameter("lastname").getBytes(), "UTF-8");
> gibts entsprechend:
> ö ä ü Ã? Ã? Ã?
Wie waer's denn mal ohne die Umcodierung? Also nur
setCharacterEncoding("utf-8") und kein new String(...).
Um die ganze Chose mal zusammenzufassen: Tomcat 3.2 hat wirklich
alles, was an Parametern reinkam, als ISO-8859-1 interpretiert. Neuere
Versionen kuemmern sich brav um das angegebene Encoding, was leider
auch nix hilft, da scheinbar so ziemlich alle Browser es nicht fuer
noetig halten, diese Angabe mitzuschicken.
Man sollte also ueberpruefen, ob ein Encoding angegeben wurde. Falls
ja, kann man davon ausgehen, dass der Client schon wusste, was er
einem da erzaehlt, und kann bei einem neueren Tomcat auch davon
ausgehen, dass der die Parameter entsprechend interpretiert. Also ist
alles im Lack. Leider scheint das nie der Fall zu sein, wenn man den
Client nicht gerade selber geschrieben hat.
Wenn kein Encoding angegeben wurde, gibt es zwei Strategien:
- Man weiss, dass der Tomcat dann per Default ISO-8859-1 annimmt. Also
kann man getBytes("iso-8859-1") auf die Parameter loslassen. Dann hat
man die wieder die urspruengliche Bytesequenz und kann sie dann
'richtig' in einem neuen String als UTF-8 interpretieren.
- Man nutzt die Methode setCharacterEncoding(), die offensichtlich als
Reaktion auf den oben beschriebenen Missstand eingefuehrt wurde. Damit
wird dann gleich alles als UTF-8 interpretiert, ohne den Umweg der
ersten Strategie.
Diese Varianten funktionieren beide natuerlich nur, wenn man
irgendeinen Grund hat, anzunehmen, dass von der anderen Seite
tatsaechlich UTF-8 geschickt wurde. Wie Tor-Einar im von Peter
geposteten Thread anmerkt, scheinen aber die gaengigen Browser
tatsaechlich fuer die Versendung der Form-Parameter das Encoding der
Seite, in der das Formular enthalten ist, zu verwenden. Wenn diese
Seite also explizit ein charset=utf-8 deklariert, hat man beste
Chancen, dass man richtig liegt. Nichtsdestotrotz hat die Sache
natuerlich immer noch eine religioese Komponente.
Was nicht taugt, ist nach dem Motto 'viel hilft viel' beide Strategien
anzuwenden. Ebenso sollte man die Methode getBytes() - nur die Version
ohne Parameter! - einfach mal aus seinem Java-Vokabular streichen, da
die spaetestens wenn mehr als ein Rechner beteiligt ist, eigentlich
nur dazu gut ist, einem auf den Fuss zu fallen.
Bleibt noch festzuhalten, dass beide Strategien nur einen mehr oder
minder dezenten Hack darstellen, weil die Browser halt Mist bauen.
Grundsaetzlich ist die Situation vergleichbar mit der
XML/DTD-Problematik: Eigentlich kann nur der Ersteller wissen, was
fuer eine DTD einem Dokument zugrundeliegt, also ist es nicht wirklich
sauber, ein Dokument gegen eine von einem spaeteren Bearbeiter fix
vorgegebene DTD zu validieren. Ebenso kann in diesem Fall eigentlich
nur der Client wissen, was fuer ein Encoding gemeint ist. Nur, dass
der sich halt vornehm in Schweigen huellt.
Puh, ich hoffe, dass ich damit den RfD fuer de.comp.lang.java.okkult
gerade noch mal abgebogen habe.
Viele Gruesse,
Patrick
Hallo Peter!
Ich habe es getestet und es funktioniert.
Nimmt Tomcat denn generell alle Umlaute entgegen, oder nur die die in
ISO-8859-1 definiert sind? Deswegen wollte ich ja UTF-8 nehmen.
Robert
Wieso? Üblicherweise werden Servlets und die HTML-Seiten von denen
sie aufgerufen werden zusammen erstellt, es ist also kein Problem,
das durchzusetzen.
Übrigens gibt es seit HTML 4.0 ein attribut "accept-charset" für
das form-tag...
> Man sollte also ueberpruefen, ob ein Encoding angegeben wurde. Falls
> ja, kann man davon ausgehen, dass der Client schon wusste, was er
> einem da erzaehlt, und kann bei einem neueren Tomcat auch davon
> ausgehen, dass der die Parameter entsprechend interpretiert. Also ist
> alles im Lack. Leider scheint das nie der Fall zu sein, wenn man den
> Client nicht gerade selber geschrieben hat.
Man kann Tomcat jedenfalls ab Version 3.3 so konfigurieren, dass UTF-8
als Standardkodierung angenommen wird. Wenn du das machst, und darauf
achtest, dass alle deine Seiten auch mit UTF-8 kodiert werden (was
kein Problem sein sollte, da dies von allen gängigen Clients
mittlerweile unterstützt wird) hast du nachher beim Lesen der
Parameter keine Probleme, egal ob sie mit GET oder POST geschickt
werden.
> Wenn kein Encoding angegeben wurde, gibt es zwei Strategien:
>
> - Man weiss, dass der Tomcat dann per Default ISO-8859-1 annimmt. Also
> kann man getBytes("iso-8859-1") auf die Parameter loslassen. Dann hat
> man die wieder die urspruengliche Bytesequenz und kann sie dann
> 'richtig' in einem neuen String als UTF-8 interpretieren.
Nein, das wird nicht immer funktionieren. UTF-8 benutzt Bytes im
Bereich 128-159 für die Kodierung, die in ISO-8859-1 nicht definiert
sind. Eine beliebige Reihe von Bytes kann also nicht ohne Verluste
nach ISO-8859-1 und zurück konvertiert werden und das ist auch der
Grund, warum hier ä, ö und ü richtig durchkommen, Ä, Ö und Ü dagegen
nicht. Die UTF-8-Kodierung der Umlaute sind:
ä 195, 164
ö 195, 182
ü 195, 188
Ä 195, 132
Ö 195, 150
Ü 195, 156
> - Man nutzt die Methode setCharacterEncoding(), die offensichtlich als
> Reaktion auf den oben beschriebenen Missstand eingefuehrt wurde. Damit
> wird dann gleich alles als UTF-8 interpretiert, ohne den Umweg der
> ersten Strategie.
Das müsste eigentlich gehen. Die einfachere Variante wäre aber Tomcat
so zu konfigurieren. Diese Methode ist aber erst in einer recht neuen
Version von der Servlet-Spezifikation enthalten, und ich dachte, dass
sie noch nicht von Tomcat unterstützt wird.
Gruß, Tor
Tor-Einar Jarnbjo wrote:
> Man kann Tomcat jedenfalls ab Version 3.3 so konfigurieren, dass UTF-8
> als Standardkodierung angenommen wird. Wenn du das machst, und darauf
> achtest, dass alle deine Seiten auch mit UTF-8 kodiert werden (was
> kein Problem sein sollte, da dies von allen gängigen Clients
> mittlerweile unterstützt wird) hast du nachher beim Lesen der
> Parameter keine Probleme, egal ob sie mit GET oder POST geschickt
> werden.
'Deine Seiten' ist ein Risikofaktor - ich hatte schon oefter mal den
Fall, dass externe Seiten meine Servlets/CGI-Scripte angesprochen haben.
Die Tomcat-Konfiguration ist eigentlich eine gute Idee, allerdings
macht man halt so den ganzen Server 'nicht standardkonform' und es
springt nicht so ins Auge, wie setCharacterEncoding() im Servlet.
> Nein, das wird nicht immer funktionieren. UTF-8 benutzt Bytes im
> Bereich 128-159 für die Kodierung, die in ISO-8859-1 nicht definiert
> sind. Eine beliebige Reihe von Bytes kann also nicht ohne Verluste
> nach ISO-8859-1 und zurück konvertiert werden und das ist auch der
> Grund, warum hier ä, ö und ü richtig durchkommen, Ä, Ö und Ü dagegen
> nicht.
Da hast Du wohl leider recht. Die verlustfreie Rueckwandlung scheint
zwar auf allen Systemen, auf denen ich es ausprobiert habe, zu
funktionieren, aber in der Doku steht ja dick und fett, dass das
Verhalten bei ungueltigen Characters nicht definiert ist.
Viele Gruesse,
Patrick
> 'Deine Seiten' ist ein Risikofaktor - ich hatte schon oefter mal den
> Fall, dass externe Seiten meine Servlets/CGI-Scripte angesprochen haben.
Warum ist das schlimm ...
> Die Tomcat-Konfiguration ist eigentlich eine gute Idee, allerdings
> macht man halt so den ganzen Server 'nicht standardkonform' und es
> springt nicht so ins Auge, wie setCharacterEncoding() im Servlet.
... und was ist daran nicht standardkonform?
> Da hast Du wohl leider recht. Die verlustfreie Rueckwandlung scheint
> zwar auf allen Systemen, auf denen ich es ausprobiert habe, zu
> funktionieren, aber in der Doku steht ja dick und fett, dass das
> Verhalten bei ungueltigen Characters nicht definiert ist.
Ja, es wird wohl so sein, dass verschiedene JDKs unter verschiedene
Betreibssysteme sich hier unterschiedlich verhalten. Wir hatten genau
das gleiche Problem mit WebLogic unter Solaris, wo die Servlet-Version
mit setCharacterEncoding noch nicht unterstützt wurde. Die
Konvertierung via ServletRequest.getParameter mit ISO-8859-1 und UTF-8
hat zwar funktioniert, aber wir haben auch eine eigene Methode in der
WebLogic-Implementation vom ServletRequest gefunden, womit wir die
Kodierung setzen konnten.
Gruß, Tor
Tor-Einar Jarnbjo wrote:
>> 'Deine Seiten' ist ein Risikofaktor - ich hatte schon oefter mal den
>> Fall, dass externe Seiten meine Servlets/CGI-Scripte angesprochen haben.
>
> Warum ist das schlimm ...
Weil die ihren Kram eventuell nicht als UTF-8 schicken.
>> Die Tomcat-Konfiguration ist eigentlich eine gute Idee, allerdings
>> macht man halt so den ganzen Server 'nicht standardkonform' und es
>> springt nicht so ins Auge, wie setCharacterEncoding() im Servlet.
>
> ... und was ist daran nicht standardkonform?
Dass als Encoding automatisch ISO-8859-1 angenommen werden soll, wenn
nicht explizit eins angegeben ist, und eben nicht 'geraten' werden
soll - so habe ich die Spec zumindest verstanden.
> Ja, es wird wohl so sein, dass verschiedene JDKs unter verschiedene
> Betreibssysteme sich hier unterschiedlich verhalten.Wir hatten genau
> das gleiche Problem mit WebLogic unter Solaris, wo die Servlet-Version
> mit setCharacterEncoding noch nicht unterstützt wurde. Die
> Konvertierung via ServletRequest.getParameter mit ISO-8859-1 und UTF-8
> hat zwar funktioniert, aber wir haben auch eine eigene Methode in der
> WebLogic-Implementation vom ServletRequest gefunden, womit wir die
> Kodierung setzen konnten.
Wie gesagt, es scheint mit den Sun-JDKs unter allen Systemen zu
funktionieren. Die Frage ist dann halt, was weniger portabel und/oder
wartungsfreundlich ist - der Konvertierungshack oder die Nutzung von
proprietaeren Serverfunktionen.
Viele Gruesse,
Patrick
> Weil die ihren Kram eventuell nicht als UTF-8 schicken.
Ach so. Du meinst, dass irgendjemand selbst Formulare anbietet, die
ihre Daten an deine Servlets schicken? Tja, das ist wohl in dem Fall
nicht dein Problem, wenn sie ihre Daten nicht richtig kodieren können?
> >> Die Tomcat-Konfiguration ist eigentlich eine gute Idee, allerdings
> >> macht man halt so den ganzen Server 'nicht standardkonform' und es
> >> springt nicht so ins Auge, wie setCharacterEncoding() im Servlet.
> >
> > ... und was ist daran nicht standardkonform?
>
> Dass als Encoding automatisch ISO-8859-1 angenommen werden soll, wenn
> nicht explizit eins angegeben ist, und eben nicht 'geraten' werden
> soll - so habe ich die Spec zumindest verstanden.
Welche Spezifikation? Nach der HTML-Spezifikation (Version 4.01),
Punkt 17.13.3 dürfen Daten, die per GET abgeschickt werden, nur
ASCII-Zeichen enthalten. Wird das Formular per POST und mit
Content-Type multipart/form-data abgeschickt, werden die Daten Nach
RFC2388 und RFC2046 kodiert, wonach US-ASCII angenommen werden soll,
wenn bei text/plain kein Zeichensatz angegeben ist und text/plain
angenommen werden soll wenn kein Content-Type überhaupt angegeben ist.
> Wie gesagt, es scheint mit den Sun-JDKs unter allen Systemen zu
> funktionieren. Die Frage ist dann halt, was weniger portabel und/oder
> wartungsfreundlich ist - der Konvertierungshack oder die Nutzung von
> proprietaeren Serverfunktionen.
Das ist schon eine gute Frage.
Gruß, Tor
Tor-Einar Jarnbjo wrote:
>> Weil die ihren Kram eventuell nicht als UTF-8 schicken.
>
> Ach so. Du meinst, dass irgendjemand selbst Formulare anbietet, die
> ihre Daten an deine Servlets schicken? Tja, das ist wohl in dem Fall
> nicht dein Problem, wenn sie ihre Daten nicht richtig kodieren können?
Sind die doch selber schuld, wenn ich frittierte Daten auf die Platte
schreibe? ;)
>> Dass als Encoding automatisch ISO-8859-1 angenommen werden soll, wenn
>> nicht explizit eins angegeben ist, und eben nicht 'geraten' werden
>> soll - so habe ich die Spec zumindest verstanden.
>
> Welche Spezifikation? Nach der HTML-Spezifikation (Version 4.01),
> Punkt 17.13.3 dürfen Daten, die per GET abgeschickt werden, nur
> ASCII-Zeichen enthalten.
Klar, aber wegen URL-Encoding bedarf es da eventuell auch der
Interpretation nach einem Encoding.
> Wird das Formular per POST und mit
> Content-Type multipart/form-data abgeschickt, werden die Daten Nach
> RFC2388 und RFC2046 kodiert, wonach US-ASCII angenommen werden soll,
> wenn bei text/plain kein Zeichensatz angegeben ist und text/plain
> angenommen werden soll wenn kein Content-Type überhaupt angegeben ist.
Ich hab's jetzt nur mal schnell ueberflogen, aber Du hast wohl recht.
Ich hatte nur in RFC2616 reingesehen und stillschweigend angenommen,
dass alles, was da ueber Default-Encodings gesagt wird,
'bidirektional' gilt.
Viele Gruesse,
Patrick