Java 如何正确解码传递给servlet的unicode参数
假设我有:Java 如何正确解码传递给servlet的unicode参数,java,unicode,servlets,Java,Unicode,Servlets,假设我有: <a href="http://www.yahoo.com/" target="_yahoo" title="Yahoo!™" onclick="return gateway(this);">Yahoo!</a> <script type="text/javascript"> function gateway(lnk) { window.open(SERVLET + '?external_lin
<a href="http://www.yahoo.com/" target="_yahoo"
title="Yahoo!™" onclick="return gateway(this);">Yahoo!</a>
<script type="text/javascript">
function gateway(lnk) {
window.open(SERVLET +
'?external_link=' + encodeURIComponent(lnk.href) +
'&external_target=' + encodeURIComponent(lnk.target) +
'&external_title=' + encodeURIComponent(lnk.title));
return false;
}
</script>
我得到雅虎!在浏览器中。如果我手动将浏览器字符编码切换为UTF-8,它将更改为Yahoo!TM(这就是我想要的)
因此我认为我发送到浏览器的编码是错误的(它是内容类型:text/html;charset=ISO-8859-1
)。我将SERVLET
更改为:
response.setContentType("text/html; charset=utf-8");
Writer writer = response.getWriter();
writer.write(request.getParameter("external_title"));
现在浏览器字符编码是UTF-8,但它输出Yahoo!而且我根本无法让浏览器呈现正确的字符
我的问题是:
内容类型
和/或新字符串(request.getParameter(“external_title”).getBytes(),“UTF-8”)是否存在某种组合代码>和/或其他将导致Yahoo!TM出现在SERVLET
输出中?您始终可以使用javascript进一步操作文本
<div id="test">a</div>
<script>
var a = document.getElementById('test');
alert(a.innerHTML);
a.innerHTML = decodeURI("Yahoo!%E2%84%A2");
alert(a.innerHTML);
</script>
a
var a=document.getElementById('test');
警报(a.innerHTML);
a、 innerHTML=decodeURI(“雅虎!%E2%84%A2”);
警报(a.innerHTML);
我怀疑请求中发生了数据损坏,即请求的声明编码与实际用于数据的编码不匹配
请求.getCharacterEncoding()
返回什么
我真的不知道JavaScript如何处理编码,也不知道如何让它使用特定的编码
您需要确保在所有阶段都正确使用编码-不要试图在数据已被错误编码的点使用newstring()
angetBytes()
来“修复”数据
编辑:将源页面(带有Javascript的页面)也编码为UTF-8并在其内容类型中声明为UTF-8可能会有所帮助。然后,我相信Javascript可能会默认使用UTF-8进行请求-但这不是确切的知识,只是猜测。我想我可以做到以下几点:
encodeURIComponent(escape(lnk.title))
这给了我%25u2122
(用于™)或%25AE
(用于®),它们将分别在servlet中解码为%u2122
和%AE
然后,我应该能够在匹配中相对轻松地使用(char)(基-10整数值%uxxx或%XX)
将%u2122转换为“\u2122”
,并使用正则表达式将%AE转换为“\u00AE”
i、 e.-match/%u([0-9a-f]{4})/i
,提取匹配的子表达式,将其转换为base-10,将其转换为字符并附加到输出,然后对/%([0-9a-f]{2})/i执行相同的操作
您就快到了。EncodeURIComponent正确地编码为UTF-8,这是您今天应该在URL中始终使用的
问题是提交的查询字符串在进入服务器端脚本的过程中被破坏,因为getParameter()使用ISO-8559-1而不是UTF-8。这源于web使用UTF-8实现URI/IRI之前的远古时代,但令人遗憾的是,Servlet规范没有更新以符合现实,或者至少没有为其提供可靠的、受支持的选项
(Servlet 2.3中有request.setCharacterEncoding,但它不会影响查询字符串解析,而且如果以前读取过单个参数(可能是由其他框架元素读取的),那么它将根本不起作用。)
因此,您需要使用特定于容器的方法来获得适当的UTF-8,通常涉及server.xml中的内容。这对于在任何地方都可以运行的网络应用来说都是糟糕透顶的。对于Tomcat,请参见和。我也遇到了同样的问题,通过使用urldecker()解码Request.getQueryString()
,并在提取参数后解决了这个问题
String[] Parameters = URLDecoder.decode(Request.getQueryString(), 'UTF-8')
.splitat('&');
有一种方法可以在java中实现(不要摆弄server.xml
)
不工作:
protected static final String CHARSET_FOR_URL_ENCODING = "UTF-8";
String uname = request.getParameter("name");
System.out.println(uname);
// ÏηγÏÏÏÏη
uname = request.getQueryString();
System.out.println(uname);
// name=%CF%84%CE%B7%CE%B3%CF%81%CF%84%CF%83%CF%82%CE%B7
uname = URLDecoder.decode(request.getParameter("name"),
CHARSET_FOR_URL_ENCODING);
System.out.println(uname);
// ÏηγÏÏÏÏη // !!!!!!!!!!!!!!!!!!!!!!!!!!!
uname = URLDecoder.decode(
"name=%CF%84%CE%B7%CE%B3%CF%81%CF%84%CF%83%CF%82%CE%B7",
CHARSET_FOR_URL_ENCODING);
System.out.println("query string decoded : " + uname);
// query string decoded : name=τηγρτσςη
uname = URLDecoder.decode(new String(request.getParameter("name")
.getBytes()), CHARSET_FOR_URL_ENCODING);
System.out.println(uname);
// ÏηγÏÏÏÏη // !!!!!!!!!!!!!!!!!!!!!!!!!!!
作品:
工作正常,但-改为尝试此操作(省略对decode()的调用,这不是必需的):
如前所述,如果server.xml
被弄乱,如:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1"
redirectPort="8443" URIEncoding="UTF-8"/>
对于多个连接器,仍然需要对此进行调整(查看注释掉的部分)。然后您将使用类似于:
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import org.apache.catalina.Server;
import org.apache.catalina.Service;
import org.apache.catalina.connector.Connector;
public class Controller extends HttpServlet {
// ...
static String CHARSET_FOR_URI_ENCODING; // the `URIEncoding` attribute
static {
MBeanServer mBeanServer = MBeanServerFactory.findMBeanServer(null).get(
0);
ObjectName name = null;
try {
name = new ObjectName("Catalina", "type", "Server");
} catch (MalformedObjectNameException e1) {
e1.printStackTrace();
}
Server server = null;
try {
server = (Server) mBeanServer.getAttribute(name, "managedResource");
} catch (AttributeNotFoundException | InstanceNotFoundException
| MBeanException | ReflectionException e) {
e.printStackTrace();
}
Service[] services = server.findServices();
for (Service service : services) {
for (Connector connector : service.findConnectors()) {
System.out.println(connector);
String uriEncoding = connector.getURIEncoding();
System.out.println("URIEncoding : " + uriEncoding);
boolean use = connector.getUseBodyEncodingForURI();
// TODO : if(use && connector.get uri enc...)
CHARSET_FOR_URI_ENCODING = uriEncoding;
// ProtocolHandler protocolHandler = connector
// .getProtocolHandler();
// if (protocolHandler instanceof Http11Protocol
// || protocolHandler instanceof Http11AprProtocol
// || protocolHandler instanceof Http11NioProtocol) {
// int serverPort = connector.getPort();
// System.out.println("HTTP Port: " + connector.getPort());
// }
}
}
}
}
new String(parameter.getBytes(CHARSET_FOR_URI_ENCODING), CHARSET_FOR_URL_ENCODING);
但是,如果parameter=request.getParameter(“name”)代码>使用字符集\u解码以进行\u URI\u编码已损坏,因此使用getBytes()获得的字节不是原始字节(这就是为什么默认情况下使用“iso-8859-1”)。您可以通过手动解析以下行中的查询字符串来消除这一切:
URLDecoder.decode(request.getQueryString().split("=")[1],
CHARSET_FOR_URL_ENCODING);
我仍然在寻找文档中提到的request.getParameter(“name”)
调用urldecker.decode()
而不是返回%CF%84%CE%B7%CE%B3%CF%81%CF%84%CF%83%CF%82%CE%B7
字符串的地方?如能在源代码中添加链接,将不胜感激。
另外,如何将字符串作为参数值传递,例如,%CE
?=>请参阅注释:参数=%25CE
Jetty的某些版本中存在一个错误,使其无法正确解析更高数量的UTF-8字符。如果您的服务器正确地接受阿拉伯语字母,但不接受表情符号,则表明您的版本存在此问题,因为阿拉伯语不在ISO-8859-1中,而是在UTF-8字符的较低范围内(“较低”表示java将以单个字符表示)
我从版本7.2.0.v20101020更新到版本7.5.4.v20111024,修复了问题;我现在可以使用getParameter(String)方法,而不必自己解析它
如果您真的很好奇,可以深入研究org.eclipse.jetty.util.Utf8StringBuilder.append(byte)的版本,看看当utf-8代码足够高时,它是否正确地向字符串添加了多个字符,或者如7.2.0所示,它只需将一个int转换为一个字符并添加后缀。感谢我对tomcat、jetty中使用的默认字符集的编码和解码所了解的一切
我用谷歌番石榴来解决我的问题
String str = URLDecoder.decode(request.getQueryString(), StandardCharsets.UTF_8.name());
final Map<String, String> map = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(str);
System.out.println(map);
System.out.println(map.get("aung"));
System.out.println(map.get("aa"));
String str=urldecker.decode(request.getQueryString(),StandardCharsets.UTF_8.name());
最终地图=
new String(parameter.getBytes(CHARSET_FOR_URI_ENCODING), CHARSET_FOR_URL_ENCODING);
URLDecoder.decode(request.getQueryString().split("=")[1],
CHARSET_FOR_URL_ENCODING);
String str = URLDecoder.decode(request.getQueryString(), StandardCharsets.UTF_8.name());
final Map<String, String> map = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(str);
System.out.println(map);
System.out.println(map.get("aung"));
System.out.println(map.get("aa"));