Java如何解码通过BeanParam接收到的GET URL参数

13

我收到了一个针对这个Web服务的GET响应。

@GET
@Path("/nnnnnn")
public Response pfpfpfpf(@BeanParam NNNNNN n)

NNNNN 包含:

@QueryParam("parameter")
private String parameter;

对于那个参数,有一个获取和设置。

我发送了一个带有查询参数的get请求,它自动绑定到我的选项NNNNN上,一切都很好。

但是,现在我正在查询url中发送日文字符串。我在发送之前使用UTF-8对参数进行编码,并且必须使用UTF-8进行解码。

但是我的问题是在哪里应该调用URLDecoder?我试图在该参数的getter中调用它,但它没有起作用,我仍然得到像C3%98%C2%B4%C3%98%C2这样的结果,而不是日文字​​符。


你可以在调用setter方法时解码(你接收到的字符串是URL编码的,你需要在存储之前解码)。 - adamdc78
我无法重现这个问题。可能是你从客户端发送的方式有问题。如果我在浏览器中测试,使用URL栏并让浏览器编码字符,它会正常显示。做这个:在你的pfpfpf方法中添加@Produces("text/plain; charset=UTF-8"),并且只返回n.getParameter()(不解码)。你会看到它可以正常工作。在浏览器中输入URL(不编码字符),你会看到结果与查询参数相同。 - Paul Samsotha
你可能进行了双重编码。你只需要编码一次,然后客户端(代理)会再次编码。这就是为什么在解码时你仍然有一个编码的字符串。 - Paul Samsotha
1
当然可以……但是按照我说的去做,你会发现它能够正常工作。那么你就知道你使用的客户端存在问题了。这里有一些需要考虑的事情:当你对日语字符进行URL编码时,你会得到像C3%98%C2%B4%C3%98%C2这样的东西。这就是所谓的URL编码。可能你使用的客户端正在对其进行再次编码。因此,你发送的不是已编码的日语字符,而是编码的编码。所以你有一个双重编码。因此,当你在服务器上接收到它时,它就是双重编码的。所以当你解码一次后,你就得到了第一个编码。 - Paul Samsotha
这就是我想要表达的观点。如果您在浏览器URL中输入日语字符,您会发现它可以正常工作。 - Paul Samsotha
显示剩余6条评论
2个回答

4
我为您提供的解决方案是:

在servlet中,我应该这样做:

request.setCharacterEncoding("UTF-8");

然后在HTML页面上,我需要添加这个:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

1

这是一个很好的问题,它有潜力消除关于系统间如何处理信息(编码和解码)的许多疑惑。

在我继续之前,我必须说对字符集、编码等有一个公平的理解。您可能想阅读this answer进行快速了解。

这必须从2个角度来看-浏览器和服务器。

浏览器编码的角度

每个浏览器都会呈现信息/文本,现在为了呈现信息/文本,它必须知道如何解释这些位/字节,以便可以正确呈现(请阅读我的答案的第3个要点,了解相同的位可以在不同的编码方案中表示不同的字符)。

浏览器页面编码

  • 每个浏览器都有与其关联的默认编码。请查看如何查看浏览器的默认编码
  • 如果您在 HTML 页面上没有指定任何编码,则浏览器的默认编码将生效,并根据这些编码规则呈现页面。因此,如果默认编码为 ASCII,而您正在使用日语或中文或 Unicode 补充平面的字符,则会看到垃圾值。
  • 您可以告诉浏览器不要使用您的默认编码方案,而是使用此编码来呈现您的网站,使用 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    • 这正是您所做/发现的,您很好,因为此 meta 标记实际上覆盖了浏览器的默认编码。
    • 实现相同效果的另一种方法是不使用此 meta 标记,而只更改浏览器的默认编码,仍然可以正常工作。但是,不建议这样做,建议在 JSP 中使用 Content-Type meta 标记。
尝试使用以下简单的HTML来玩转浏览器默认编码和标签。
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        の, は, でした <br></br>
        昨夜, 最高
    </body>        
</html>

编码的服务器视角

服务器也应该知道如何解释传入的数据流,这基本上意味着使用哪种编码方案(服务器部分很棘手,因为有几种可能性)。从这里阅读以下内容

当提交已输入到HTML表单中的数据时,表单字段名称和值将被编码并使用GET或POST方法的HTTP请求消息发送到服务器,或通过电子邮件(历史上如此)。默认情况下使用的编码基于通用URI百分比编码规则的早期版本,并进行了许多修改,例如换行符规范化以及用“+”替换空格而不是“%20”。以这种方式编码的数据的MIME类型是application/x-www-form-urlencoded,目前仍然以非常过时的方式在HTML和XForms规范中定义。此外,CGI规范包含有关Web服务器如何解码此类数据并使其可用于应用程序的规则。

这又分为两部分:服务器如何解码传入的请求流以及如何对传出的响应流进行编码。

有几种方法可以实现这个,具体根据使用情况而定,例如:

  • 在HTTP请求和响应对象中有setCharacterEncoding, setContentType等方法, 可以用来设置编码。
    • 这正是你所做的,在你的情况下,你已经告诉服务器使用UTF-8编码方案来解码请求数据,因为我期望使用先进的Unicode补充平面字符。但这还不是全部,请继续阅读以下内容。
  • 使用JVM属性如-Dfile.encoding=utf8在服务器或JVM级别上设置编码。请参考this article了解如何设置服务器编码。

在你的情况下,你从URL的查询字符串中获取了日语字符,而查询字符串是HTTP请求对象的一部分,因此使用request.setCharacterEncoding("UTF-8");,你可以得到所需的编码结果。

但是对于URL编码来说,情况并非如此,它与请求编码不同(您的情况)。请考虑以下示例,在两个sysout中,即使使用了request.setCharacterEncoding("UTF-8");,您也无法看到所需的编码效果,因为在这里您需要进行URL编码,因为URL将是类似于http://localhost:7001/springapp/forms/executorTest/encodingTest/hellothere 昨夜, 最高的东西,并且在此URL中没有查询字符串。
@RequestMapping(value="/encodingTest/{quertStringValue}", method=RequestMethod.GET)
    public ModelAndView encodingTest(@PathVariable("quertStringValue") String quertStringValue, ModelMap model, HttpServletRequest request) throws UnsupportedEncodingException {
        System.out.println("############### quertStringValue " + quertStringValue);
        request.setCharacterEncoding("UTF-8");
        System.out.println("############### quertStringValue " + quertStringValue);
        return new ModelAndView("ThreadInfo", "ThreadInfo", "@@@@@@@ This is my encoded output " + quertStringValue);
    }

根据您使用的框架,您可能需要进行额外的配置以指定请求或URL的字符编码,以便在请求未指定编码时应用自己的编码,或者无论如何都强制执行编码。这很有用,因为当前的浏览器通常不会设置字符编码,即使在HTML页面或表单中指定了编码。
在Spring中,有org.springframework.web.filter.CharacterEncodingFilter来配置请求编码。阅读this similar interesting question,该问题基于此事实。
简而言之,每个计算机程序(无论是应用程序服务器、Web服务器、浏览器、IDE等)只能理解位,因此它需要知道如何解释位以使其产生预期的意义,因为根据使用的编码,相同的位可以表示不同的字符。这就是“编码”的作用,通过给出一个唯一的标识符来表示一个字符,以便所有计算机程序、多样化的操作系统等都知道确切的正确解释方式。

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