java编码问题:“圣保罗”变成“S%C3%A3o%20Paulo”,然后变成“圣保罗”
我有一个Spring应用程序遇到一些编码问题。当客户提交“圣保罗”时,我在请求头中看到:
=============>>> url is: /users/1825220/activity=update_fields&hometown=S%C3%A3o%20Paulo&usrId=1234 (PUT)
这是通过在请求传入时将其转储到日志中生成的
logger.info("\n=============>>> url is: " + request.getRequestURI() + "/" + request.getQueryString() + " (" + request.getMethod() + ")");
然后将请求传递给方法:
@RequestMapping(value = "/users/{id}", method = RequestMethod.PUT)
public @ResponseBody
OperationResponse updateUser(HttpServletRequest request,
@PathVariable("id") Integer id,
@RequestParam(value = "hometown", required = false) String homeTown)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
当我转储值时:
logger.debug("HOMETOWN=" + homeTown);
我得到:家乡=圣保罗
我对编码的基础知识有点熟悉,所有的东西看起来都是UTF-8,但显然我还不太了解这一点。我已经看到了一些关于这方面的主题,即使是使用相同的数据,但我没有找到任何能够完全解决这一问题的方法
我发现这些值是正确的。e、 g.ã(在圣保罗)有这些十六进制值。 http://www.utf8-chartable.de/
U+00A3 £ c2 a3 POUND SIGN
U+00C3 Ã c3 83 LATIN CAPITAL LETTER A WITH TILDE
U+00E3 ã c3 a3 LATIN SMALL LETTER A WITH TILDE
从本机iOS应用程序和网站以及通过curl输入的值相同。 出于某种原因,ã(U+00E3)被分解为4个字节(%C3%A3),而不是2个字节(%E3)。 我就是想不出断开的地方在哪里
我需要做的是最好弄清楚在配置中更改什么,而不是在数据进入的任何地方都添加代码更改
# 1 楼答案
0xE3
(顺便说一句,这仅仅是1个字节)是大多数8位编码中的值,尤其是iso8859和cp1252然而,为了更好的兼容性,url编码通常在UTF-8中完成。因此是2个字节,
0xC3 0xA3
在您的情况下,您的服务器正在读取它,好像它不是1个utf-8字符,而是2个iso(或cp)字符。结果就是这样
AgilePro建议的解决方案在大多数情况下都会起作用,但是通过将服务配置为接受UTF-8或确保客户机指示他们使用的编码来解决实际问题会更为简洁
这个问题可能与这个问题有关:Spring MVC UTF-8 Encoding
# 2 楼答案
您遇到的问题是标准UTF-8编码问题,如果URL参数没有按正确的顺序解码,通常会出现这种问题
对于UTF-8,大于127的任何字符值都转换为多字节序列,该序列仅由大于127的字节值组成。所以你的ã被正确地编码成两个字节的值。然后将字节值转换为URL编码使用的%xx符号
要对此进行解码,您需要做相反的操作:将%表示法转换为字节流,然后使用UTF-8编码将字节转换为字符串。问题是,有些环境以错误的顺序执行此操作:它们将字节流转换为字符串(解码UTF-8),然后处理URL编码。那是错误的顺序
有一种蛮力解决方案可以恢复yur值,即获取损坏的值,将其转换回字节,然后转换成如下字符串:
这是一段相当难看的代码,但它会将字符转换回原处
将HTTPRequest对象设置为UTF-8模式可以解决此问题。这样做:
这可能对春天有用。。。我不确定头是什么时候被解析的。在TomCat的情况下,如果您使用的是JSP文件,但在调用JSP文件时,进行此设置已经太晚了。标题将已被解析。解决这一问题的官方最佳方法是在解析标头和调用JSP之前,在请求对象中插入一个过滤器,以进行此设置。如果您发现设置字符编码不起作用。。。试试过滤器
我在别处读到,您可以在Spring中启用这样一个过滤器,并在您的web中使用此设置。xml(但我没有这方面的经验):