环境:POST方法、Content-Type: application/x-www-form-urlencoded;charset=utf-8(key=val&key2=val2形式)

调用接口:commons-httpclient-3.1

服务接口:springboot-1.4.2.release/spring-web-4.3.4.release

场景:通常在对接第三方系统中可能双方采用的编码不一致 从而导致令人头疼的中文乱码问题。而通常需要在header和param两个地方需要设置charset字符编码;另外由于技术框架不同,charset的默认设置也有差异;有些只需在param处设置即可,而有些必须在header也设置;当然一般两者都设置并相同最好。

所遇问题:对于第三方接口就必须要在header中设置charset编码,然而自己写的spring服务测试则不用,原因是spring默认设置字符编码为UTF-8,可以通过配置更改,只有在charset=null时才会从Content-Type中取charset作为反编码的字符集。

一:调用接口:

header中设置method.addRequestHeader(entry.getKey(), entry.getValue());

param中设置method.getParams().setContentCharset(charset);

        Map<String, String> headers = ImmutableMap.of("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");try {String resp = LargeHttpUtils.doPost(url, params, "utf-8", headers);} catch (HttpException e) {e.printStackTrace();}

1、请求数据格式转换,并进行编码

    // 实际上key=val&key2=val2形式的参数都会转换为RequestEntity结构protected RequestEntity generateRequestEntity() {if (!this.params.isEmpty()) {// 对传输数据进行编码,获取charset方法getRequestCharSet()String content = EncodingUtil.formUrlEncode(this.getParameters(), this.getRequestCharSet());ByteArrayRequestEntity entity = new ByteArrayRequestEntity(EncodingUtil.getAsciiBytes(content), "application/x-www-form-urlencoded");return entity;} else {return super.generateRequestEntity();}}

2、getRequestCharSet()获取charset字符编码:这里处理的方法是 先从header中拿charset,拿不到再从param中拿;如果同时设置 相当于param中的charset不起作用

    public String getRequestCharSet() {// 可以看到这里是判断header中有没有设置Content-Typeif (this.getRequestHeader("Content-Type") == null) {return this.requestEntity != null ? this.getContentCharSet(new Header("Content-Type", this.requestEntity.getContentType())) : super.getRequestCharSet();} else {return super.getRequestCharSet();}}public String getRequestCharSet() {// 从header中取出Content-Typereturn this.getContentCharSet(this.getRequestHeader("Content-Type"));}protected String getContentCharSet(Header contentheader) {LOG.trace("enter getContentCharSet( Header contentheader )");String charset = null;// 如果设置了Content-Type并且设置了charset,则直接返回 作为请求数据的字符编码if (contentheader != null) {HeaderElement[] values = contentheader.getElements();if (values.length == 1) {NameValuePair param = values[0].getParameterByName("charset");if (param != null) {charset = param.getValue();}}}// 如果以上条件不满足 则从param中设置的拿到charset编码 作为请求数据的字符编码if (charset == null) {charset = this.getParams().getContentCharset();if (LOG.isDebugEnabled()) {LOG.debug("Default charset used: " + charset);}}return charset;}

二、服务接口:

1、HttpEncodingProperties这配置的目的是设置chaset进行数据的反编码,应用程序启动时加载,可以在yaml文件中配置:

spring:http:encoding:charset: UTF-8
@ConfigurationProperties(prefix = "spring.http.encoding"
)
public class HttpEncodingProperties {public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");private Charset charset;private Boolean force;private Boolean forceRequest;private Boolean forceResponse;private Map<Locale, Charset> mapping;public HttpEncodingProperties() {this.charset = DEFAULT_CHARSET;}public Charset getCharset() {return this.charset;}public void setCharset(Charset charset) {this.charset = charset;}

2、Spring应用有一个过滤器 来对请求和响应的数据charset统一处理:

public class CharacterEncodingFilter extends OncePerRequestFilter {private String encoding;private boolean forceRequestEncoding;private boolean forceResponseEncoding;.....public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) {this.forceRequestEncoding = false;this.forceResponseEncoding = false;Assert.hasLength(encoding, "Encoding must not be empty");this.encoding = encoding;this.forceRequestEncoding = forceRequestEncoding;this.forceResponseEncoding = forceResponseEncoding;}protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 这里就会拿到上面配置的charsetString encoding = this.getEncoding();if (encoding != null) {// 这里其实就和servlet中的request.setCharacterEncoding() 作用一样if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {request.setCharacterEncoding(encoding);}if (this.isForceResponseEncoding()) {response.setCharacterEncoding(encoding);}}filterChain.doFilter(request, response);}
}

3、在Request类中通过getCharacterEncoding获取charset

    // 获取charsetpublic String getCharacterEncoding() {// 这里先尝试从request拿charset(上面在字符过滤器中设置的)if (this.charEncoding != null) {return this.charEncoding;} else {// 拿不到在从Content-Type中获取charsetthis.charEncoding = getCharsetFromContentType(this.getContentType());return this.charEncoding;}}

4、数据反编码:在Request中通过parseParameters进行反编码数据

    protected void parseParameters() {this.parametersParsed = true;Parameters parameters = this.coyoteRequest.getParameters();boolean success = false;try {parameters.setLimit(this.getConnector().getMaxParameterCount());// 这里获取到charset(上面的方法)String enc = this.getCharacterEncoding();boolean useBodyEncodingForURI = this.connector.getUseBodyEncodingForURI();if (enc != null) {parameters.setEncoding(enc);if (useBodyEncodingForURI) {parameters.setQueryStringEncoding(enc);}} else {parameters.setEncoding("ISO-8859-1");if (useBodyEncodingForURI) {parameters.setQueryStringEncoding("ISO-8859-1");}}// 解析url中的参数parameters.handleQueryParameters();if (this.usingInputStream || this.usingReader) {success = true;} else if (!this.getConnector().isParseBodyMethod(this.getMethod())) {success = true;} else {String contentType = this.getContentType();if (contentType == null) {contentType = "";}int semicolon = contentType.indexOf(59);if (semicolon >= 0) {contentType = contentType.substring(0, semicolon).trim();} else {contentType = contentType.trim();}if ("multipart/form-data".equals(contentType)) {this.parseParts(false);success = true;} else if (!"application/x-www-form-urlencoded".equals(contentType)) {success = true;} else {int len = this.getContentLength();if (len <= 0) {if ("chunked".equalsIgnoreCase(this.coyoteRequest.getHeader("transfer-encoding"))) {Object var21 = null;......if (formData != null) {// 解析formData数据parameters.processParameters(formData, 0, formData.length);}}} else {int maxPostSize = this.connector.getMaxPostSize();Context context;if (maxPostSize >= 0 && len > maxPostSize) {context = this.getContext();if (context != null && context.getLogger().isDebugEnabled()) {context.getLogger().debug(sm.getString("coyoteRequest.postTooLarge"));}.........// 解析formData数据parameters.processParameters(formData, 0, len);}success = true;}}} finally {if (!success) {parameters.setParseFailedReason(FailReason.UNKNOWN);}}}

不当之处,欢迎指出 谢谢!

Charset编码问题导致的中文乱码相关推荐

  1. Mysql自动超时重连导致的中文乱码问题

    Mysql自动超时重连导致的中文乱码问题 今天有客户反应从自选股服务器获取的自定义板块中文名称乱码,之前一直都是正常的.看到乱码两字,头脑中首先冒出来的就是查看mysql数据库中的编码集,输入SHOW ...

  2. java locale中文_locale错误导致Java中文乱码错误的总结

    线上执行MapReduce任务计算时,经过排查发现了某些服务器计算的数据出现中文乱码问题,但是服务器的配置是完全一致的.由于我们使用的key可能包含中文,中文乱码问题体现在每次合并map记录的时候计算 ...

  3. c# mysql 编码_c# 连接MySQL中文乱码问题的正确方案

    以下的文章主要向大家介绍的是c# 连接MySQL中文乱码问题的正确解决方法,一开始不太清楚为什么整个数据库的默认配置都为utf-8,而且有些人在使用http协议传送utf-8的汉字时,是正确的执行了的 ...

  4. utf-8编码引起js输出中文乱码的解决办法

    如果web application的编码规则是utf-8,如网页头中的: <meta http-equiv="Content-Type" content="text ...

  5. 【记录】关于编码格式导致的中文乱码问题

    一. 问题描述 最近有个需求,解压压缩包提取其中的文件,处理rar.7z格式没啥问题,处理解压zip(项目中用的版本比较老)的时候,解压方法中需要传入编码格式,问题就来了. 使用windows系统打包 ...

  6. Spring MVC 3.2+ @ResponseBody 导致的中文乱码处理

    2019独角兽企业重金招聘Python工程师标准>>> 问题原因是spring mvc中竟然使用了ISO-编码 这个问题看了好几个,有的配置AnnotationMethodHandl ...

  7. 解决前后端base64编码传递时的中文乱码问题

    1 前端JavaScript加密 window.btoa(unescape(encodeURIComponent(str))) 2 后端Java解密 String decode = new Strin ...

  8. Idea 设置编码UTF-8 Idea中 .properties 配置文件中文乱码

    Idea 设置编码UTF-8 Idea中 .properties 配置文件中文乱码 一.设置编码 1.步骤: File -> Setting -> Editor -> File en ...

  9. 从本机发送信息到另一台服务器上时中文乱码

    2019独角兽企业重金招聘Python工程师标准>>> 从本机发送信息到另一台服务器上时中文乱码 别的电脑都没问题,只有本机通过sts开tomcat并发送信息到另一服务器时中文乱码. ...

最新文章

  1. Google Protocol Buffer 简单介绍
  2. 【深度学习】卷积神经网络速成
  3. 微软与联合国环境规划署联手解决环境问题
  4. 如何查看光驱硬盘托架的尺寸_如何确定光驱位的硬盘托架的大小尺寸和接口
  5. 公关文秘专业要学计算机,文秘相关专业有哪些
  6. 荣耀正式加入GSMA 成为其企业成员单位
  7. Unity3D-后期处理 Post-process Volume Profile
  8. STM32+IR2104S的H桥电机驱动电路详解
  9. 今夜,只我一人听雨声
  10. 红外接收二极管为什么正反都能通_为什么在电路板中测量二极管正反都通
  11. 谢孟媛老师 初级文法学习笔记
  12. 软件测试DAY3-执行用例
  13. 常用工具软件的交叉编译
  14. pip 生成 requirement.txt 文件
  15. Google浏览器被劫持解决方法
  16. ctab法提取dna流程图_CTAB法提取DNA
  17. docker 执行py文件
  18. 微信公众号发布svg排版文章
  19. 自媒体运营、平面设计封面如何搭配?3大色彩搭配网站推荐
  20. 北京队“接触风波”受罚背后:CBA职业化不断进步

热门文章

  1. 推荐几个牛叉技术大神的高质量免费技术专栏,码洞垫底
  2. 外汇天眼:美联储认为美国房价有大跌的风险!
  3. XP桌面上伪IE图标删除方法
  4. 赛效:PDF电子文档怎么转HTML?
  5. 网球裙行业调研报告 - 市场现状分析与发展前景预测
  6. Canvas 从入门到劝朋友放弃(图解版)
  7. 河师大583C语言,焦照勇 - 河南师范大学 - 物理学院
  8. JavaScript中的定时控制-Throttle、Debounce、Immediate的基本概念
  9. 智能ABC中快速切换 输入特殊符号
  10. AI「独角兽」企业!快商通厚积薄发,获福建省官方盖戳!