[scode type=“share”]今天在使用activeMQ-web的使用数据返回到前端一直中文乱码,本来以为是activeMQ的原因,应该可以设置字符集。看了看它的源码,并没有提供设置字符集的地方。[/scode]
乱码的本质
乱码无非就是前端和后端使用的字符集不一致,解决的方法就是把字符集设置为一致。统一字符集一般设置为utf-8。
查看源码
在使用ActiveMQ-web的时候配置了一个Servlet,这个Servlet类是AjaxServlet,发送的请求都去这里了。AjaxServlet 继承 MessageListenerServlet,在MessageListenerServlet中看到了这一段代码处理消息的响应
StringWriter swriter = new StringWriter();
PrintWriter writer = new PrintWriter(swriter);
Map<MessageAvailableConsumer, String> consumerIdMap = client.getIdMap();
Map<MessageAvailableConsumer, String> consumerDestinationNameMap = client.getDestinationNameMap();
response.setStatus(200);
writer.println("<ajax-response>");
String m;
if (message != null) {
String id = (String)consumerIdMap.get(consumer);
m = (String)consumerDestinationNameMap.get(consumer);
LOG.debug("sending pre-existing message");
this.writeMessageResponse(writer, message, id, m);
++messages;
}
LinkedList<UndeliveredAjaxMessage> undeliveredMessages = ((AjaxListener)consumer.getAvailableListener()).getUndeliveredMessages();
LOG.debug("Send " + undeliveredMessages.size() + " unconsumed messages");
synchronized(undeliveredMessages) {
Iterator it = undeliveredMessages.iterator();
while(it.hasNext()) {
++messages;
UndeliveredAjaxMessage undelivered = (UndeliveredAjaxMessage)it.next();
Message msg = undelivered.getMessage();
consumer = (MessageAvailableConsumer)undelivered.getConsumer();
String id = (String)consumerIdMap.get(consumer);
String destinationName = (String)consumerDestinationNameMap.get(consumer);
LOG.debug("sending undelivered/buffered messages");
LOG.debug("msg:" + msg + ", id:" + id + ", destinationName:" + destinationName);
this.writeMessageResponse(writer, msg, id, destinationName);
it.remove();
if (messages >= this.maximumMessages) {
break;
}
}
}
for(int i = 0; i < consumers.size() && messages < this.maximumMessages; ++i) {
consumer = (MessageAvailableConsumer)consumers.get(i);
if (consumer.getAvailableListener() != null) {
while(messages < this.maximumMessages) {
message = consumer.receiveNoWait();
if (message == null) {
break;
}
++messages;
String id = (String)consumerIdMap.get(consumer);
String destinationName = (String)consumerDestinationNameMap.get(consumer);
LOG.debug("sending final available messages");
this.writeMessageResponse(writer, message, id, destinationName);
}
}
}
writer.print("</ajax-response>");
writer.flush();
m = swriter.toString();
response.getWriter().println(m);
这里只需要知道它使用了response返回数据,在调试的时候看消息文本并没有乱码,返回到前端就乱码了,初步分析是因为response设置的字符集不是utf-8。
解决方案
response乱码解决有三种方式:
- response.setCharacterEncoding("utf-8”);//设置服务器端的编码,默认是ISO-8859-1
- response.setContentType("text/html;charset=utf-8”);
- response.getWriter().println("”);
不管哪一种其实都要通过设置response对象参数来解决,但是这个response对象在activemq-web的源码里面,我们改动不了。只能通过拦截器来实现设置字符集了,每次请求进过拦截器,设置字符集。
初步解决(踩坑)
在SpringBoot中配置拦截器
@Configuration
public class ServletConfig {
//注册AjaxServlet,使用activemq-web所需
@Bean
public ServletRegistrationBean activemqRegistration() {
AjaxServlet ajaxServlet = new AjaxServlet();
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(ajaxServlet);
servletRegistrationBean.addUrlMappings("/amq");
return servletRegistrationBean;
}
//解决中文乱码,注册拦截器
@Bean
public FilterRegistrationBean charsetRegistration(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter("utf-8",true);
filterRegistrationBean.setFilter(characterEncodingFilter);
return filterRegistrationBean;
}
}
配置完了之后发现,明明启用了设置respspon字符集但是拦截的时候forceResponseEncoding这个属性的值还是一直为false。看看这一段代码:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encoding = this.getEncoding();
if (encoding != null) {
if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}
if (this.isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}
filterChain.doFilter(request, response);
}
可以看到当forceResponseEncoding为false的时候根本不会设置字符集。
最终解决
springboot自动配置就配置了字符集拦截器,所以覆盖了我们配置的这个。在application.yml配置文件里面可以直接设置字符拦截器的一系列属性。在里面加上
spring:
http:
encoding:
force-response: true
到这里问题就解决了