如何在Java中正确地创建mailto URL(URI)?

17

给定:

String email1 = "simple@example.org";

// legal email address according to wikipedia [1]
String email2 = "\"()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a\"@example.org";

什么是创建mailto: URI(以字符串对象形式)的最佳/正确方式?
我尝试过:
String uri = new URI("mailto", the_email_address, null).toString();

这是我找到的最接近的答案,但它没有对电子邮件地址的本地部分中的问号(?)进行编码,但根据RFC 6068,应该进行编码。 它还不能处理RFC中的示例,例如"not@me"@example.orgunlikely?address@example.com
[1] 有效电子邮件地址示例 附注:mailto:超链接中应该对加号进行编码吗?中有一些有用的信息。

我接受了这个作为解决方案:

import org.apache.http.client.utils.URIBuilder;
// from Apache HttpClient
// maven group: org.apache.httpcomponents artifact: httpclient

String emailURL = new URIBuilder().setScheme("mailto").setPath(the_email_address).toString();

我注意到你的示例从email1创建了一个URI,但它没有问号,你是不是想使用email2? - Benjamin Confino
问号在另一个例子中。那个评论是通用的:如果电子邮件地址中有问号,则使用的方法无法正常工作。 - David Balažic
@DavidBalažic 你不能使用Apache Commons URI Builder吗?还是你的需求不同? - Jishnu Prathap
3个回答

12

你需要手动对问号 (?) 和与符号 (&) 进行百分号编码 / 转义。

String email2 = "\"()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a\"@example.org";
String uri2 = (new URI("mailto", email2, null)).toString().replace("?", "%3F").replace("&", "%26");
因为URI中的?&符号没有被正确转义,所以URI中的?后面的任何内容都会被忽略,因为该符号在URL中保留用于"查询字符串"。请参考这里
根据此文档和参考文献,我们还需要将&进行转义。由于某种原因,Java没有为我们执行此操作。实际上,RFC 6068甚至指出:
  

一些字符可能会出现在URI中,必须进行百分比编码。     这些是按照[STD66]不能出现在URI中的字符,以及“%”(因为它用于     百分比编码)和gen-delims中除“@”和“:”之外的所有字符     即“ /”,“?”,“#”,“ [”和“]”)。在字符中     sub-delims中,至少还需要将以下内容进行百分比编码:"&",";"和"="。

修复它的方法(有点hack,但它有效)是手动使用%后跟符号的2位ASCII十六进制值来转义这些字符。请参考这里
我通过将生成的字符串粘贴到Chrome中进行测试,可以正确打开我的默认电子邮件并编写一封邮件给
"()<>[]:,; @\"!#$%&'*+-/=?^_`{}| ~.a"@example.org

更多研究

因此,似乎Java的URI类使用RFC 2396,其中规定:

如果URI组件的数据与保留用途冲突,则在形成URI之前必须对冲突数据进行转义。

 reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
            "$" | ","

"reserved"这个语法类指的是URI中允许出现的字符,但是在通用URI语法的特定组件中可能不被允许出现;


4

您需要使用Apache Commons URI构建器

该值应为未转义的,可能包含非ASCII字符。

您不能直接使用java uri类 Java URI文档 指出:
所有标点符号字符与字符串"?/[]@"中的字符一起保留

Java's URI class uses RFC 2396, which states:If the data for a URI component would conflict with the reserved purpose, then the conflicting data must be escaped before forming the URI.

 reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
            "$" | ","

You can use java.net.URLEncoder to encode the user_name and then use encoded username to create the URI String uri = new URI("mailto", the_email_address, null).toString(); or
You can manually percent encode/escape the ? and &.

String email2 = "\"()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a\"@example.org";
String uri2 = (new URI("mailto", email2, null)).toString().replace("?", "%3F").replace("&", "%26");

In JavaScript you can use the encodeURI() function. PHP has the rawurlencode() function, and ASP has the Server.URLEncode() function.



0
你可能想要使用URI.create(String uri)静态方法来创建你的mailto URI,而不是使用“new”构造函数。例如,这将返回一个有效的URI(我正在使用jdk 7):
URI.create("mailto:john?doe@foo.bar.com");

希望能对你有所帮助。

祝好。


JavaDoc说:“此方法适用于已知给定字符串是合法URI的情况”,因此当我已经有解决方案时,我可以使用此方法。 ;) - David Balažic

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