这是一个很好的问题,它有潜力消除关于系统间如何处理信息(编码和解码)的许多疑惑。
在我继续之前,我必须说对字符集、编码等有一个公平的理解。您可能想阅读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等)只能理解位,因此它需要知道如何解释位以使其产生预期的意义,因为根据使用的编码,相同的位可以表示不同的字符。这就是“编码”的作用,通过给出一个唯一的标识符来表示一个字符,以便所有计算机程序、多样化的操作系统等都知道确切的正确解释方式。
pfpfpf
方法中添加@Produces("text/plain; charset=UTF-8")
,并且只返回n.getParameter()
(不解码)。你会看到它可以正常工作。在浏览器中输入URL(不编码字符),你会看到结果与查询参数相同。 - Paul SamsothaC3%98%C2%B4%C3%98%C2
这样的东西。这就是所谓的URL编码。可能你使用的客户端正在对其进行再次编码。因此,你发送的不是已编码的日语字符,而是编码的编码。所以你有一个双重编码。因此,当你在服务器上接收到它时,它就是双重编码的。所以当你解码一次后,你就得到了第一个编码。 - Paul Samsotha