example - java encoding windows 1252
¿Hay alguna forma de usar UTF-8 con el motor de aplicaciones? (4)
Estoy buscando alguna explicación sobre cómo el motor de la aplicación se ocupa de las codificaciones de caracteres. Estoy trabajando en una aplicación cliente-servidor donde el servidor está en el motor de la aplicación.
Esta es una nueva aplicación construida desde cero, por lo que estamos usando UTF-8 en todas partes. El cliente envía algunas cadenas al servidor a través de POST, x-www-form-urlencoded. Los recibo y los echo de vuelta. Cuando el cliente lo recupera, ¡es ISO-8859-1! También veo este comportamiento al realizar la POST en la tienda de blob, con los parámetros enviados como UTF-8, multipart / form-data codificada.
Para el registro, estoy viendo esto en Wireshark. Así que estoy 100% seguro de enviar UTF-8 y recibir ISO-8859-1. Además, no estoy viendo mojibake: las cadenas codificadas ISO-8859-1 están perfectamente bien. Esto tampoco es un problema de malinterpretar el tipo de contenido. No es el cliente. Algo en el camino es reconocer correctamente que estoy enviando parámetros UTF-8, pero por algún motivo los está convirtiendo a ISO-8859-1.
Me hacen creer que ISO-8859-1 es la codificación de caracteres predeterminada para los servlets de GAE. Mi pregunta es, ¿hay alguna manera de decirle a GAE que no convierta a ISO-8859-1 y en su lugar use UTF-8 en todas partes?
Digamos que el servlet hace algo como esto:
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setContentType("application/json");
String name = req.getParameter("name");
String json = "{/"name/":/"" + name + "/"}";
resp.getOutputStream().print(json);
}
Traté de configurar la codificación de caracteres de la respuesta y la solicitud a "UTF-8", pero eso no cambió nada.
Gracias por adelantado,
Solución (segura)
Ninguna de estas respuestas funcionó para mí, así que escribí esta clase para codificar UTF-Strings en ASCII-Strings (reemplazando todos los caracteres que no están en la tabla ASCII con su número de tabla, precedido y seguido de una marca), usando AsciiEncoder.encode(yourString)
La cadena se puede decodificar de nuevo a UTF con AsciiEncoder.decode(yourAsciiEncodedString)
.
package <your_package>;
import java.util.ArrayList;
/**
* Created by Micha F. aka Peracutor.
* 04.06.2017
*/
public class AsciiEncoder {
public static final char MARK = ''%''; //use whatever ASCII-char you like (should be occurring not often in regular text)
public static String encode(String s) {
StringBuilder result = new StringBuilder(s.length() + 4 * 10); //buffer for 10 special characters (4 additional chars for every special char that gets replaced)
for (char c : s.toCharArray()) {
if ((int) c > 127 || c == MARK) {
result.append(MARK).append((int) c).append(MARK);
} else {
result.append(c);
}
}
return result.toString();
}
public static String decode(String s) {
int lastMark = -1;
ArrayList<Character> chars = new ArrayList<>();
try {
//noinspection InfiniteLoopStatement
while (true) {
String charString = s.substring(lastMark = s.indexOf(MARK, lastMark + 1) + 1, lastMark = s.indexOf(MARK, lastMark));
char c = (char) Integer.parseInt(charString);
chars.add(c);
}
} catch (IndexOutOfBoundsException | NumberFormatException ignored) {}
for (char c : chars) {
s = s.replace("" + MARK + ((int) c) + MARK, String.valueOf(c));
}
return s;
}
}
Espero que esto ayude a alguien.
Encontré una forma de evitarlo. Así es como lo hice:
Se utilizó "application / json; charset = UTF-8" como tipo de contenido. Alternativamente, configure el conjunto de caracteres de respuesta en "UTF-8" (cualquiera funcionará bien, no es necesario que haga ambas cosas).
Base64 codifica las cadenas de entrada que no son ASCII-safe y vienen como UTF-8. De lo contrario, se convierten a ISO-8859-1 cuando llegan al servlet, al parecer.
Usado resp.getWriter () en lugar de resp.getOutputStream () para imprimir la respuesta JSON.
Después de que se cumplieron todas esas condiciones, finalmente pude devolver UTF-8 al cliente.
Esto no es específico de GAE, pero en caso de que lo encuentre útil: hice mi propio filtro:
En web.xml
<filter>
<filter-name>charsetencoding</filter-name>
<filter-class>mypackage.CharsetEncodingFilter</filter-class>
</filter>
...
<filter-mapping>
<filter-name>charsetencoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(coloque el fragmento de mapeo de filtro bastante al comienzo de las asignaciones de filtro y verifique su patrón de url).
Y
public class CharsetEncodingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
req.setCharacterEncoding("UTF-8");
chain.doFilter(req, res);
res.setCharacterEncoding("UTF-8");
}
public void destroy() { }
public void init(FilterConfig filterConfig) throws ServletException { }
}
Veo dos cosas que debes hacer.
1) configure las propiedades del sistema (si lo está usando) para utf8 en su appengine-web.xml
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
<property name="file.encoding" value="UTF-8" />
<property name="DEFAULT_ENCODING" value="UTF-8" />
</system-properties>
De acuerdo que arriba es lo que tengo pero los documentos sugieren esto a continuación:
<env-variables>
<env-var name="DEFAULT_ENCODING" value="UTF-8" />
</env-variables>
https://developers.google.com/appengine/docs/java/config/appconfig
2) especifique la codificación cuando configure el tipo de contenido o volverá a ser el predeterminado
El tipo de contenido puede incluir el tipo de codificación de caracteres utilizada, por ejemplo, text / html; charset = ISO-8859-4.
Lo intentaría
resp.setContentType("application/json; charset=UTF-8");
También puede probar con un escritor que le permita establecer el tipo de contenido directamente.
http://docs.oracle.com/javaee/1.3/api/javax/servlet/ServletResponse.html#getWriter%28%29
http://docs.oracle.com/javaee/1.3/api/javax/servlet/ServletResponse.html#setContentType(java.lang.String)
Por lo que vale, necesito utf8 para contenido japonés y no tengo problemas. No estoy usando un filtro o setContentType de todos modos. Estoy usando gwt y # 1 arriba y funciona.