有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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)。 我就是想不出断开的地方在哪里

我需要做的是最好弄清楚在配置中更改什么,而不是在数据进入的任何地方都添加代码更改


共 (2) 个答案

  1. # 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. # 2 楼答案

    您遇到的问题是标准UTF-8编码问题,如果URL参数没有按正确的顺序解码,通常会出现这种问题

    对于UTF-8,大于127的任何字符值都转换为多字节序列,该序列仅由大于127的字节值组成。所以你的ã被正确地编码成两个字节的值。然后将字节值转换为URL编码使用的%xx符号

    要对此进行解码,您需要做相反的操作:将%表示法转换为字节流,然后使用UTF-8编码将字节转换为字符串。问题是,有些环境以错误的顺序执行此操作:它们将字节流转换为字符串(解码UTF-8),然后处理URL编码。那是错误的顺序

    有一种蛮力解决方案可以恢复yur值,即获取损坏的值,将其转换回字节,然后转换成如下字符串:

    String val = new String(oldval.getBytes("iso-8859-1"), "UTF-8");
    

    这是一段相当难看的代码,但它会将字符转换回原处

    将HTTPRequest对象设置为UTF-8模式可以解决此问题。这样做:

    request.setCharacterEncoding("UTF-8");
    

    这可能对春天有用。。。我不确定头是什么时候被解析的。在TomCat的情况下,如果您使用的是JSP文件,但在调用JSP文件时,进行此设置已经太晚了。标题将已被解析。解决这一问题的官方最佳方法是在解析标头和调用JSP之前,在请求对象中插入一个过滤器,以进行此设置。如果您发现设置字符编码不起作用。。。试试过滤器

    我在别处读到,您可以在Spring中启用这样一个过滤器,并在您的web中使用此设置。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>  
    <filter-mapping>  
        <filter-name>encodingFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>