Текст UTF-8 искажается, когда форма публикуется как multipart/form-data
Я загружаю файл на сервер. HTML-форма для загрузки файла имеет 2 поля:
- Имя файла - текстовое поле HTML, где пользователь может дать имя на любом языке.
- Загрузка файла - файл HTMl, в котором пользователь может указать файл с диска для загрузки.
Когда форма отправлена, содержимое файла получено правильно. Однако когда имя файла (пункт 1 выше) читается, оно искажается. Символы ASCII отображаются правильно. Когда имя дается на каком-то другом языке (немецком, французском и т. Д.), Возникают проблемы.
В методе сервлета кодировка символов запроса установлена в UTF-8. Я даже попытался сделать фильтр, как упомянуто - Как я могу сделать этот код для отправки текстовой области формы UTF-8 с работой jQuery/Ajax? - но это не похоже на работу. Только имя файла искажено.
Таблица MySQL, в которую входит имя файла, поддерживает UTF-8. Я дал случайные неанглийские символы, и они хранятся / отображаются правильно.
Используя Fiddler, я следил за запросом и все данные POST передаются правильно. Я пытаюсь определить, как / где данные могут быть искажены. Любая помощь будет оценена.
12 ответов
У меня была такая же проблема при использовании Apache commons-fileupload. Я не выяснил, что вызывает проблемы, особенно потому, что у меня есть кодировка UTF-8 в следующих местах: 1. Метатег HTML 2. Атрибут accept-charset формы 3. Фильтр Tomcat при каждом запросе, который устанавливает "UTF-8" кодирование
-> Мое решение заключалось в особом преобразовании строк из ISO-8859-1 (или любой другой кодировки по умолчанию для вашей платформы) в UTF-8:
new String (s.getBytes ("iso-8859-1"), "UTF-8");
надеюсь, это поможет
Редактировать: начиная с Java 8 вы также можете использовать следующее:
new String (s.getBytes (StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
Просто используйте Apache Commons для загрузки библиотеки. добавлять URIEncoding="UTF-8"
к соединителю Tomcat и используйте FileItem.getString("UTF-8") вместо FileItem.getString() без указания кодировки.
Надеюсь, это поможет.
Я застрял с этой проблемой и обнаружил, что это был заказ вызова
request.setCharacterEncoding("UTF-8");
это было причиной проблемы. Он должен вызываться перед любым вызовом метода request.getParameter(), поэтому я создал специальный фильтр для использования в верхней части цепочки фильтров.
http://www.ninthavenue.com.au/servletrequest-setcharactercoding-ignored
У меня была такая же проблема, и оказалось, что помимо указания кодировки в фильтре
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
необходимо добавить в форму "acceptcharset"
<form method="post" enctype="multipart/form-data" acceptcharset="UTF-8" >
и запустить JVM с
-Dfile.encoding=UTF-8
Метатег HTML не требуется, если вы отправляете его в заголовке HTTP с использованием response.setCharacterEncoding().
Если кто-то натолкнулся на эту проблему при работе с веб-приложением Grails (или чистого Spring), вот пост, который мне помог:
http://forum.spring.io/forum/spring-projects/web/2491-solved-character-encoding-and-multipart-forms
Чтобы установить кодировку по умолчанию UTF-8 (вместо ISO-8859-1) для многочастных запросов, я добавил следующий код в resources.groovy (Spring DSL):
multipartResolver(ContentLengthAwareCommonsMultipartResolver) {
defaultEncoding = 'UTF-8'
}
Я использую org.apache.commons.fileupload.servlet.ServletFileUpload.ServletFileUpload(FileItemFactory)
и определение кодировки при считывании значения параметра:
List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (FileItem item : items) {
String fieldName = item.getFieldName();
if (item.isFormField()) {
String fieldValue = item.getString("UTF-8"); // <-- HERE
Фильтр является ключевым для IE. Несколько других вещей, чтобы проверить;
Какая кодировка страницы и набор символов? Оба должны быть UTF-8
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
Что такое набор символов в метатеге?
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
В строке подключения MySQL указано UTF-8? например
jdbc:mysql://127.0.0.1/dbname?requireSSL=false&useUnicode=true&characterEncoding=UTF-8
Я использую Primefaces с Glassfish и SQL Server.
в моем случае я создал Webfilter в бэк-энде, чтобы получать каждый запрос и конвертировать в UTF-8, например так:
package br.com.teste.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
@WebFilter(servletNames={"Faces Servlet"})
public class Filter implements javax.servlet.Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
В представлении (.xhtml) мне нужно задать для формы параметра энктипа значение UTF-8, например @Kevin Rahe:
<h:form id="frmt" enctype="multipart/form-data;charset=UTF-8" >
<!-- your code here -->
</h:form>
Чтобы избежать ручного преобразования всех параметров запроса в UTF-8, вы можете определить метод, аннотированный с помощью @InitBinder
в вашем контроллере:
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new CharacterEditor(true) {
@Override
public void setAsText(String text) throws IllegalArgumentException {
String properText = new String(text.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
setValue(properText);
}
});
}
Вышеупомянутое автоматически преобразует все параметры запроса в UTF-8 в контроллере, где он определен.
Вы также должны убедиться, что ваш фильтр кодирования (org.springframework.web.filter.CharacterEncodingFilter) в вашем файле web.xml сопоставлен перед многочастным фильтром (org.springframework.web.multipart.support.MultipartFilter).
У меня такая же проблема. Единственное решение, которое работало для меня, это добавление
Я думаю, что опаздываю на вечеринку, но когда вы используете wildfly, вы можете добавить кодировку по умолчанию в standalone.xml. Просто найдите в standalone.xml для
<servlet-container name="default">
и добавьте кодировку следующим образом:
<servlet-container name="default" default-encoding="UTF-8">
Фильтр и настройка Tomcat для поддержки URI UTF-8 важны только в том случае, если вы передаете через строку запроса URL-адреса, как если бы вы использовали HTTP GET. Если вы используете POST со строкой запроса в теле HTTP-сообщения, важен тип содержимого запроса, и браузер должен установить тип содержимого в UTF-8 и отправить контент с этой кодировкой.
Единственный способ сделать это - сообщить браузеру, что вы можете принимать только UTF-8, устанавливая заголовок Accept-Charset при каждом ответе на "UTF-8;q=1,ISO-8859-1;q=0,6"., Это сделает UTF-8 лучшим качеством и кодировку по умолчанию, ISO-8859-1, приемлемой, но более низкого качества.
Когда вы говорите, что имя файла искажено, оно искажено в возвращаемом значении HttpServletRequest.getParameter?
Вы не используете UTF-8 для кодирования текстовых данных для HTML-форм. Стандарт html определяет две кодировки, и соответствующая часть этого стандарта находится здесь. "Старая" кодировка, чем обрабатывает ascii, является application/x-www-form-urlencoded. Новый, который работает правильно, является multipart/form-data.
В частности, объявление формы выглядит так:
<FORM action="http://server.com/cgi/handle"
enctype="multipart/form-data"
method="post">
<P>
What is your name? <INPUT type="text" name="submit-name"><BR>
What files are you sending? <INPUT type="file" name="files"><BR>
<INPUT type="submit" value="Send"> <INPUT type="reset">
</FORM>
И я думаю, что это все, что вам нужно беспокоиться - веб-сервер должен справиться с этим. Если вы пишете что-то, что непосредственно читает InputStream из веб-клиента, то вам нужно будет прочитать RFC 2045 и RFC 2046.