Servlet请求参数字符编码

11

我有一个Java Servlet,通过HTTP GET请求从上游系统接收数据。该请求包含一个名为"text"的参数。如果上游系统将该参数设置为:

TEST3 please ignore:

它在上游系统的日志中出现为:

00 54 00 45 00 53 00 54 00 33 00 20 00 70 00 6c   //TEST3 pl
00 65 00 61 00 73 00 65 00 20 00 69 00 67 00 6e   //ease ign
00 6f 00 72 00 65 00 3a                           //ore:   

(注释实际上不会出现在日志中)

在我的servlet中,我使用以下代码读取此参数:

String text = request.getParameter("text");

如果我将text的值打印到控制台上,它会显示为:
T E S T 3  p l e a s e  i g n o r e :

如果我在调试器中检查text的值,它会显示为:
\u000T\u000E\u000S\u000T\u0003\u0000 \u000p\u000l\u000e\u000a\u000s\u000e\u0000 
\u000i\u000g\u000n\u000o\u000r\u000e\u000:

似乎字符编码存在问题。上游系统应该使用UTF-16。我猜测Servlet假定为UTF-8,因此读取的字符数是实际字符数的两倍。对于消息“TEST3请忽略:”,每个字符的第一个字节是00。当Servlet读取时,这被解释为空格,这解释了在Servlet记录消息时出现在每个字符之前的空格。
显然,我的目标只是在读取text请求参数时获得消息“TEST3请忽略:”。我猜想可以通过指定请求参数的字符编码来实现这一点,但我不知道如何做到这一点。

1
GET参数必须是ASCII或URL编码的,不能在其中使用特殊字符集。 - Maurício Linhares
你使用的Web容器是什么?你的HTML文件字符集是什么? - Pau Kiat Wee
或许这个链接可以帮助解决问题:https://dev59.com/L3A75IYBdhLWcg3weY5f - Kazekage Gaara
1
@MaurícioLinhares,你有这个声明的链接吗? - Dónal
是的 - http://zh.wikipedia.org/wiki/百分号编码#当前标准 - Maurício Linhares
3个回答

9

使用方法如下

new String(req.getParameter("<my request value>").getBytes("ISO-8859-1"),"UTF-8")

1
这解决了我的问题,但我不完全明白为什么... :( - pataluc
6
我深入挖掘后发现,调用 request.setCharacterEncoding("UTF-8"); 是我唯一需要的事情(而且更有意义)。 - pataluc

2
尝试使用Filter进行此操作。
public class CustomCharacterEncodingFilter implements Filter {

    public void init(FilterConfig config) throws ServletException {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
                                                       throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }

    public void destroy() {
    }

这应该为整个应用程序设置编码。

1

看起来它是使用 UTF-16LE(小端)编码进行编码的,这里有一个成功打印您字符串的类:

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;

public class Test {
    public static void main(String[] args) throws UnsupportedEncodingException {
            String hex = "00 54 00 45 00 53 00 54 00 33 00 20 00 70 00 6c"  +
                            "00 65 00 61 00 73 00 65 00 20 00 69 00 67 00 6e" +
                           "00 6f 00 72 00 65 00 3a"; // + " 00";
            System.out.println(new String(new BigInteger(hex.replaceAll(" ", ""), 16).toByteArray(), "UTF-16LE"));
    }
}

输出:

TEST3 please ignore?

将输入值加上两个零输出

TEST3 please ignore:

更新

要使此功能与您的Servlet配合使用,您可以尝试:

  String value = request.getParameter("text");
  try {
      value = new String(value.getBytes(), "UTF-16LE");
  } catch(java.io.UnsupportedEncodingException ex) {}

更新

请查看以下链接,它验证了生成的十六进制实际上是UTF-16LE


最后一个字符应该是“:”,而不是“?”。 - Dónal
@Don,这是因为3a缺少最后的00,如果你添加它,它就可以正确解码。要么该字符串的编码器出了问题,要么你可能忘记复制最后两个零了。 - epoch
你说得对,可能是我复制粘贴时出错了。顺便问一下,你确定这不是大端字节序吗?感谢你的帮助。 - Dónal
没问题,我不是字符编码方面的专家,但我非常确定它是小端序,因为大端序根本无法解码该字符串 :) - epoch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接