springboot下使用HttpServletResponse API回写‘text/html‘数据时的中文乱码问题

15 篇文章 0 订阅

boot版本:2.6.4

这阵子做开发,用到了callback jsonp。

之前对这种方式返回的数据中文编码问题没有特别注意过,出现了乱码(想想确实啊,这个小问题应该早就注意到,惭愧惭愧)。因此,这里特别做了多个实验返回”text/html“数据,查看其编码情况,不为别的,就是为了加深记忆和理解。

首先是,咱们先只考虑在controller内部处理乱码问题,如何解决呢?

函数内部解决

response回写

首先是,直接采用response的writer回写数据

案例一

代码

 public void sss(HttpServletRequest request, HttpServletResponse response) {
        String sss = "北京你好!-jfQQQQ";
        try {
//            response.setCharacterEncoding("utf-8");
//            response.setHeader("Content-Type", "text/html; charset=utf-8");
//            response.setHeader("Content-Type","text/html");
            PrintWriter writer = response.getWriter();
            writer.write(sss.toCharArray());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

结果

页面上查看

响应信息查看

 

案例二

在案例一的基础上将文字内容进行utf8编码化再返回

代码

public void sss(HttpServletRequest request, HttpServletResponse response) {
        String sss = "北京你好!-jfQQQQ";
        try {
            response.setCharacterEncoding("utf-8");
//            response.setHeader("Content-Type", "text/html; charset=utf-8");
//            response.setHeader("Content-Type","text/html");
            PrintWriter writer = response.getWriter();
            writer.write(sss.toCharArray());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

结果

页面上查看

响应信息查看

 

 

 

可以看到,已经不是“ ?”号了。

 案例三

案例二基础上,增加返回数据类型说明。 

代码

  public void sss(HttpServletRequest request, HttpServletResponse response) {
        String sss = "北京你好!-jfQQQQ";
        try {
            response.setCharacterEncoding("utf-8");
//            response.setHeader("Content-Type", "text/html; charset=utf-8");
            response.setHeader("Content-Type","text/html");
            PrintWriter writer = response.getWriter();
            writer.write(sss.toCharArray());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

结果

页面上查看

响应信息查看

 

 

可以看到,已经可以显示正常的中文了 。并且,springboot自动增加了“charset=utf8”字样。

所以,下边的代码与上方代码效果一致:

public void sss(HttpServletRequest request, HttpServletResponse response) {
        String sss = "北京你好!-jfQQQQ";
        try {
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Type", "text/html; charset=utf-8");
//            response.setHeader("Content-Type","text/html");//springboot在返回时会自动增加“charset=utf8”字样,所以效果同上方代码
            PrintWriter writer = response.getWriter();
            writer.write(sss.toCharArray());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

案例四

在拼写“content-type”字样时会容易出现拼错了的情况,response API里有直接设置响应头的办法,就很省事:

代码

public void sss(HttpServletRequest request, HttpServletResponse response) {
        String sss = "北京你好!-jfQQQQ";
        try {
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/html; charset=utf-8");
//            response.setHeader("content-tYpE", "text/html; charset=utf-8");
//            response.setHeader("Content-Type","text/html");//springboot在返回时会自动增加“charset=utf8”字样,所以效果同上方代码
            PrintWriter writer = response.getWriter();
            writer.write(sss.toCharArray());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

结果

  

案例五

这是一个错误的使用案例,“content-type”很容易写错,或者有时候由于理解不透彻导致拼写错误,包括在不明所以的情况下,不知道 大小写 以及 “-” 的影响。所以,值得仔细测试一下,并总结下来

代码

    public void sss(HttpServletRequest request, HttpServletResponse response) {
        String sss = "北京你好!-jfQQQQ";
        try {
            response.setCharacterEncoding("utf-8");
            response.setHeader("contentType", "text/html; charset=utf-8");//contentType拼写不对,应该是Content-Type
            PrintWriter writer = response.getWriter();
            writer.write(sss.toCharArray());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

结果

页面上查看:

响应头查看

 

 

原因是“Content-Type”写成了“contentType”。

于是,我又新奇的这样写:contenttype,效果与上面一样。

但是,这样写:content-type,就正确了,查看响应头:

 于是,我又这样写:content-tYpE,依旧是正确的可以的。

所以,只要把content和type之间用“-”连接,就行了,不用在乎大小写。

案例六

基于案例一,在函数上方增加produces配置

代码

这里简化代码,只保留了增加produces配置的部分:

 @GetMapping(value = "/info",produces = "text/html;charset=utf-8")

结果

同案例一,没有任何效果。

因为案例一的行为是自己的response的输出,脱离了spring,

通过类比,可以发现是由于response返回的header中没有指定content-type类型和编码导致的。

Springboot的注解使用案例

ok,上面是虽然在springboot下,但是根本没有使用springboot特性(除了案例六,不过虽然写了produces,但是实际上也是没用到的)。那么使用springboot的特性也是会有这种情况的。

案例一

代码

    @ResponseBody
    public String findCurrentUserInfo2(HttpServletRequest request) {
        String sss = "北京你好!-jfQQQQ";
        return sss;
    }

结果

 

这也说明了当前springboot上下文默认使用的是ISO-8859-1编码。所以,前面的response的使用时也是由于这个原因,由此,这里抛出一个更好的解决办法:直接设定springboot的编码。

 案例二

直接返回字节数组,考虑编码为utf-8.

代码

    @ResponseBody
    public byte[] findCurrentUserInfo2(HttpServletRequest request) {
        String sss = "北京你好!-jfQQQQ";
        return sss.getBytes(StandardCharsets.UTF_8);
    }

结果

 

 

这种情况下,页面展示是乱码,是由于response header中没有指定编码,但是对于获取到数据的js代码来说,是可以自行解码使用的。 

案例三

就是在produces里增加了“text/html;charset=utf-8”设置

代码

 @GetMapping(value = "/info",produces = "text/html;charset=utf-8")
    @ResponseBody
    public String findCurrentUserInfo2(HttpServletRequest request) {
        String sss = "北京你好!-jfQQQQ";
        return sss;//.getBytes(StandardCharsets.UTF_8);
    }

结果

 

 

注意:不加上charset的设置,就是失败的:

默认用了ISO的! 

函数外部解决

直接设定springboot的编码

server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=truer

然后在此基础上,实验案例若干:

response直接写

案例一

public void sss(HttpServletRequest request, HttpServletResponse response) {
        String sss = "北京你好!-jfQQQQ";
        try {
//            response.setCharacterEncoding("utf-8");
//            response.setContentType("text/html; charset=utf-8");
//            response.setHeader("content-tYpE", "text/html; charset=utf-8");
//            response.setHeader("Content-Type","text/html");//springboot在返回时会自动增加“charset=utf8”字样,所以效果同上方代码
            PrintWriter writer = response.getWriter();
            writer.write(sss.toCharArray());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

结果

  

 不起作用。。。。

springboot特性

案例一

代码

    @ResponseBody
    public String findCurrentUserInfo2(HttpServletRequest request) {
        String sss = "北京你好!-jfQQQQ";
        return sss;//.getBytes(StandardCharsets.UTF_8);
    }

结果

 

不起作用。。。 

案例二

基于案例一给produces增加

produces = "text/html;"

的设置,注意,没有指定“charset=utf-8”!

结论就是依旧不行:

并且可见原因是编码为ISO了!可是明明有调试源码,utf-8的properties设定的实体类有被创建,并且值就是utf-8啊!难道没用到那个类?(org.springframework.boot.web.servlet.server.Encoding) 

分析源码

结合上面的案例,得出的结论是我们配置的properties并没有起到作用,那么我们就需要找到起到作用的类和方法,spring中转换消息的类一般都是“***Convertor”,再加上我们返回的是text/html,类似于string,所以自然是找到了org.springframework.http.converter.StringHttpMessageConverter类,果不其然,里面的编码默认是ISO:

 so,我们来调试一下,看看返回数据的时候是不是用到了它。

ok,确认了。

接下来,跟源码(org.springframework.http.converter.StringHttpMessageConverter中),返回数据时,会有一个判断响应头的逻辑,如果controller的函数返回时没有满足if中判断的条件:

 那么,就执行默认的响应头(调用到了org.springframework.http.converter.AbstractHttpMessageConverter中的addDefaultHeaders方法),如下图:

同时,由于我只配置了produces为“text/html”,所以上面的断点处,就走到了获取

his.getDefaultCharset();

这一句,要去获取默认的charset,我们看看它要去从哪里获取:

还是org.springframework.http.converter.AbstractHttpMessageConverter中,它自己存储了默认的编码值:

 这个defaultCharset是在创建时指定的,截图时是utf-8。

不过这个属性是在创建时指定的,我们看看这个属性是在哪里赋值的。

赋值是在创建时指定的(org.springframework.http.converter.AbstractHttpMessageConverter):

 上面的创建是在下图被调用的

然后上图是在下图被调用的

然后下图就是上图用到的默认编码值,于是走到迷宫尽头了,可以出宫了。

结论

所以,关键问题就在于我们让springboot启动初始化时,将类的默认编码换为utf-8就行了,而那个类是StringHttpMessageConverter 。

所以,我们要这样自创建一个bean,设定它的类别,再注入到spring上下文中,替换其默认的bean。

这样:

@Bean
public HttpMessageConverter<String> responseBodyConverter() {
   StringHttpMessageConverter converter = new StringHttpMessageConverter(
         Charset.forName("UTF-8"));
   return converter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
   super.configureMessageConverters(converters);
   converters.add(responseBodyConverter());
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
   configurer.favorPathExtension(false);
}
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

	@Bean
	public HttpMessageConverter<String> responseBodyConverter() {
		StringHttpMessageConverter converter = new StringHttpMessageConverter(
				Charset.forName("UTF-8"));
		return converter;
	}
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		super.configureMessageConverters(converters);
		converters.add(responseBodyConverter());
	}
	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		configurer.favorPathExtension(false);
	}

}

用这种方式配置后,就可以不在controller中做特殊处理来使用了。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Spring Boot,如果要设置HttpServletResponse参数,可以通过以下步骤进行操作: 1. 在Spring Boot应用程序的启动类中,添加一个@Bean注解的方法,该方法返一个CharacterEncodingFilter对象。该对象用于设置HttpServletResponse的编码为UTF-8。可以使用如下代码: ```java import org.springframework.context.annotation.Bean; import org.springframework.web.filter.CharacterEncodingFilter; @SpringBootApplication public class YourApplication { @Bean public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("UTF-8"); filter.setForceEncoding(true); return filter; } // 其他代码... } ``` 2. 设置CharacterEncodingFilter的编码为UTF-8,并将forceEncoding属性设置为true,以确保所有响应都使用UTF-8编码。这样,当Spring Boot应用程序处理HttpServletResponse,响应的编码将始终是UTF-8。 通过以上步骤,可以在Spring Boot应用程序中设置HttpServletResponse参数来使用指定的编码。这样可以确保响应中的字符在传输过程中不会出现码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [springboot使用HttpServletResponse APItext/html数据中文问题](https://blog.csdn.net/jfqqqqq/article/details/124005319)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值