如何配置Spring Boot处理Windows-1252编码的JSON请求?
解决Spring Boot 2中Windows-1252编码JSON请求乱码问题
问题根源
Spring Boot默认的MappingJackson2HttpMessageConverter仅默认处理UTF-8编码的请求,当客户端发送application/json; charset=Windows-1252格式的请求时,转换器未按指定编码解码请求体,导致乱码。以下是两种可行的解决方案:
方案一:自定义MappingJackson2HttpMessageConverter(推荐)
通过扩展Spring MVC的消息转换器,让Jackson支持Windows-1252编码的JSON请求,符合Spring Boot的原生设计逻辑。
创建Web MVC配置类:
import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.List; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); // 添加支持Windows-1252编码的JSON媒体类型 MediaType windows1252Json = MediaType.APPLICATION_JSON.withCharset(Charset.forName("Windows-1252")); jsonConverter.getSupportedMediaTypes().add(windows1252Json); // 保留默认UTF-8支持,确保兼容原有正常请求 jsonConverter.setDefaultCharset(StandardCharsets.UTF_8); // 将自定义转换器放在首位,优先使用 converters.add(0, jsonConverter); } }
补充说明
如果需要调整Jackson的序列化/反序列化规则,可以给转换器绑定自定义ObjectMapper:
ObjectMapper customMapper = new ObjectMapper(); // 例如允许未转义的控制字符等 customMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); jsonConverter.setObjectMapper(customMapper);
方案二:自定义请求编码转换过滤器
若方案一未生效,可通过自定义过滤器在请求到达Spring MVC组件前,将Windows-1252编码的请求体转换为UTF-8,确保后续流程正常处理。
创建过滤器类:
import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @Component @Order(Ordered.HIGHEST_PRECEDENCE) // 确保过滤器最先执行 public class Windows1252EncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String contentType = httpRequest.getContentType(); // 仅处理Windows-1252编码的JSON请求 if (contentType != null && contentType.contains("application/json") && contentType.contains("charset=Windows-1252")) { byte[] rawBody = readRawRequestBody(httpRequest); // 用Windows-1252解码请求体,再转成UTF-8字节流 String bodyStr = new String(rawBody, Charset.forName("Windows-1252")); byte[] utf8Body = bodyStr.getBytes(StandardCharsets.UTF_8); // 包装请求,替换输入流为UTF-8编码的内容 HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper(httpRequest) { @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(utf8Body), StandardCharsets.UTF_8)); } @Override public ServletInputStream getInputStream() throws IOException { return new ServletInputStream() { private final ByteArrayInputStream inputStream = new ByteArrayInputStream(utf8Body); @Override public int read() throws IOException { return inputStream.read(); } @Override public boolean isFinished() { return inputStream.available() == 0; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener listener) {} }; } }; chain.doFilter(wrappedRequest, response); } else { // 其他请求直接放行 chain.doFilter(request, response); } } // 读取原始请求体字节数组 private byte[] readRawRequestBody(HttpServletRequest request) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int bytesRead; try (ServletInputStream inputStream = request.getInputStream()) { while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } } return outputStream.toByteArray(); } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
方案选择建议
优先使用方案一,因为它直接集成在Spring MVC的消息转换体系中,更贴合框架设计,维护成本更低;若方案一无法解决问题(比如存在其他自定义转换器干扰),再尝试方案二的过滤器方案。
内容的提问来源于stack exchange,提问作者Murillo Goulart
相关产品推荐
相关产品推荐

