HttpServletResponse通过setContentType设置响应头失败,以及解决办法

1 背景

1.1 版本信息

  • springcloud版本:Dalston.SR1
  • springboot版本:1.5.3.Release
  • JDK版本:1.8

1.2 缺陷描述

当我从Controller或者ControllerAdvice直接返回一个JSON字符串时,通过response.setContentType("application/json;charset=UTF-8");失败,前端实际拿到的content-type为text/plain;charset=UTF-8.如果前端对头部有校验的话,很可能会出现拿不到数据的情况.以下为示例代码,当调用/fail接口就可以看到结果

  • 全局异常处理类
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public Object defaultHandler(HttpServletResponse response,Exception e) throws JsonProcessingException {
        log.error(e.getMessage(),e);
        response.setContentType("application/json;charset=UTF-8");
        if(e instanceof PSQLException
                || e instanceof PersistenceException
                || e instanceof MyBatisSystemException
                || e instanceof BadSqlGrammarException){
            return  ResultObject.exception(1,"内部错误:数据库操作失败");
        }

        if(e instanceof HttpHostConnectException
                || e instanceof RetryableException){
            return ResultObject.exception(1,"连接失败:请检查第三方系统接入状态");
        }

        return "{\n" +
                "  \"code\": 1,\n" +
                "  \"msg\": \"未知错误,请联系管理员\"\n" +
                "}";
    }

}
  • controller层代码
@Api(value = "测试", tags = "测试")
@RequestMapping("/test")
@RestController
public class TestController {

    @GetMapping(value = "/fail")
    @ApiOperation("失败")
    public String fail() {
        int i=1/0;
        return "fail";
    }

  
}

swagger调用结果:

  • 响应结果是正常的json串
    在这里插入图片描述
  • 头部信息异常
    在这里插入图片描述

2 解决办法

目前尚未查到具体原因,但是通过设置@RequestMapping中的produces属性可以达到修改响应头的目的

3 总结

当你出现以下状况

  • 响应体为正常json串
  • 通过response的setHeader或者setContentType修改content-type
  • 前端接收的响应头信息为:text/plain;charset=UTF-8
  • controller层返回类型为String,而不是对象

那么!!可以尝试修改RequestMapping代码
@GetMapping(value = "/fail",produces="application/json;charset=UTF-8")


虽然这不是最好的办法,但是可以临时解决一下问题,与君共勉
<think>嗯,用户遇到了Servlet在工作台中显示中文乱码的问题,该怎么解决呢?首先,我需要回忆一下常见的乱码原因和解决办法。可能涉及到编码设置的几个方面,比如请求和响应的编码、服务器的默认编码,还有数据库或者文件读取时的编码问题。 首先,用户提到的是工作台中的中文乱码,可能是在控制台输出时出现的问题。这时候要考虑Servlet在输出到控制台时使用的编码是否正确。比如,System.out.println输出中文字符,如果IDE的控制台编码设置不正确,可能会导致乱码。不过更常见的是在HTTP响应中的乱码,比如浏览器显示乱码,但用户明确说是工作台,也就是控制台,可能需要检查IDE的编码设置,比如Eclipse或IntelliJ的配置文件,确保它们使用UTF-8编码。 但用户的问题是关于Servlet的,可能更多是在处理请求和响应时出现的乱码。比如,当Servlet接收客户端传来的数据,或者向客户端返回数据时,没有正确设置字符编码,导致乱码。这时候需要分情况讨论:GET和POST请求的处理可能不同,因为GET请求的参数通常是通过URL传递的,而POST请求的参数在请求体中。 对于POST请求,通常需要在获取参数之前设置请求的编码。比如,使用request.setCharacterEncoding("UTF-8"),但需要注意的是,这个方法只对POST请求有效,对GET请求无效。GET请求的参数在Tomcat等服务器中解码时,默认使用的是ISO-8859-1,所以需要手动将参数重新编码。例如,String name = new String(request.getParameter("name").getBytes("ISO-8859-1"), "UTF-8")。 另外,响应输出的编码也需要设置,包括设置响应的内容类型和字符编码。response.setContentType("text/html;charset=UTF-8"),或者分开设置response.setCharacterEncoding("UTF-8")。同时,确保PrintWriter在设置编码之后获取,因为setCharacterEncoding需要在getWriter之前调用才有效。 还有可能是数据库连接的问题,如果Servlet从数据库读取数据出现乱码,需要检查数据库的连接字符串是否指定了正确的编码,比如jdbc:mysql://...?useUnicode=true&characterEncoding=UTF-8。 还有文件编码的问题,比如Servlet源文件本身是否以UTF-8保存,编译后的class文件是否正确,但现代IDE一般会自动处理,不过有时候配置错误也可能导致问题。 另外,服务器的配置也很重要,比如Tomcat的server.xml中的Connector是否设置了URIEncoding="UTF-8",以处理GET请求的URL参数编码。 总结一下,可能的解决步骤是: 1. 检查并设置请求编码,特别是POST请求的setCharacterEncoding。 2. 处理GET请求参数时手动转码。 3. 设置响应的内容类型和字符编码。 4. 确保服务器(如Tomcat)的配置正确。 5. 检查IDE控制台的编码设置是否为UTF-8。 6. 验证数据库和文件读取时的编码设置。 需要逐步排查这些方面,确定问题出现的环节,再针对性地解决。比如用户如果是在控制台输出乱码,可能问题出在Servlet内部处理字符串时的编码,或者IDE的设置。如果是浏览器显示乱码,则更可能是响应编码的问题。所以需要用户明确乱码发生的具体场景,但用户已经提到是工作台,所以可能偏向于控制台输出或者日志的情况,这时候要检查系统输出流的编码和IDE的设置。</think>以下分步骤解决Servlet中文乱码问题: 一、请求阶段编码设置 1. POST请求处理 $$request.setCharacterEncoding("UTF-8");$$ 需在首次调用request.getParameter()前执行 2. GET请求特殊处理 $$String param = new String(request.getParameter("name").getBytes("ISO-8859-1"), "UTF-8");$$ 二、响应阶段编码设置 1. 设置双重保障 $$response.setContentType("text/html;charset=UTF-8");$$ $$response.setCharacterEncoding("UTF-8");$$ 2. 输出流优先级 ```java // 必须在获取Writer前设置 PrintWriter out = response.getWriter(); ``` 三、服务器配置优化 1. Tomcat配置(server.xml) ```xml <Connector port="8080" URIEncoding="UTF-8" .../> ``` 2. Web.xml过滤器 ```xml <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> ``` 四、开发环境校验 1. IDE设置检查 - Eclipse:Window > Preferences > General > Workspace > Text file encoding - IntelliJ:File > Settings > Editor > File Encodings 2. 文件存储编码验证 确保.java文件本身使用UTF-8保存 五、数据库连接层 JDBC URL添加参数: $$jdbc:mysql://host/db?useUnicode=true&characterEncoding=UTF-8$$ 六、测试验证方案 1. 创建测试Servlet ```java protected void doPost(HttpServletRequest request, HttpServletResponse response) { try { request.setCharacterEncoding("UTF-8"); String test = request.getParameter("test"); System.out.println("控制台输出:" + test); response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("响应输出:" + test); } catch (IOException e) { e.printStackTrace(); } } ``` 2. 使用Postman发送测试 设置请求头: $$Content-Type: application/x-www-form-urlencoded; charset=UTF-8$$ 七、特殊场景处理 1. 二进制流传输 ```java // 下载文件时强制指定编码 response.setHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes("UTF-8"), "ISO-8859-1")); ``` 2. AJAX请求处理 前端统一设置: ```javascript $.ajaxSetup({ contentType: "application/x-www-form-urlencoded;charset=utf-8" }); ``` 排查建议: 1. 使用Chrome开发者工具检查 - Network标签查看实际传输编码 - 检查Request Headers和Response Headers 2. 字节级调试 ```java // 输出原始字节查看编码 byte[] bytes = param.getBytes(); System.out.println(Arrays.toString(bytes)); ``` 典型错误对照表: | 现象 | 可能原因 | 解决方案 | |----------------------|-------------------------|----------------------------| | 问号?? | ISO-8859-1转UTF-8失败 | 检查getBytes()转换编码 | | 菱形符号� | 字符集不兼容 | 统一所有环节为UTF-8 | | 控制台正常浏览器乱码 | 缺失response编码设置 | 添加response.setContentType | | 部分页面乱码 | 过滤器配置不完整 | 检查web.xml过滤器顺序 | 通过以上步骤的系统性排查,可解决90%以上的Servlet中文乱码问题。建议按照请求处理流程逐步验证各环节编码设置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值