Lotus 在通过带有 OpenURL 命令的 Java WebAgent 接收 POST 时更改的字符
Characters altered by Lotus when receiving a POST through a Java WebAgent with OpenURL command
我在 Lotus-Domino 中有一个 Java WebAgent,它通过 OpenURL 命令 (https://link.com/db.nsf/agentName?openagent) 运行。创建此代理是为了接收包含 XML 内容的 POST。在解析或保存 (XML) 内容之前,webagent 将内容保存到内存中的文档中:
For an agent run from a browser with the OpenAgent URL command, the
in-memory document is a new document containing an item for each CGI
(Common Gateway Interface) variable supported by Domino®. Each item
has the name and current value of a supported CGI variable. (No design
work on your part is needed; the CGI variables are available
automatically.)
https://www.ibm.com/support/knowledgecenter/en/SSVRGU_9.0.1/basic/H_DOCUMENTCONTEXT_PROPERTY_JAVA.html
POST 的内容将(由 Lotus)保存到 request_content
字段中。当接收到带有此字符的内容时:é,如:
<Name xml:lang="en">tést</Name>
Lotus 将 é 更改为 ?®。这也是我在读取文档属性中的 request_content
字段时看到的。是否可以在 Lotus 中将 é 保存为 é 而不是 a: ?®?
解决方法:
我修复它的方法是通过 post:
Link which help me solve this problem
但在Java中的解决方案:
/****** INITIALIZATION ******/
session = getSession();
AgentContext agentContext = session.getAgentContext();
Stream stream = session.createStream();
stream.open("C:\Temp\test.txt", "LMBCS");
stream.writeText(agentContext.getDocumentContext().getItemValueString("REQUEST_CONTENT"));
stream.close();
stream.open("C:\Temp\test.txt", "UTF-8");
String Content = stream.readText();
stream.close();
System.out.println("Content: " + Content);
我以前处理过这个问题,但我无法再访问代码,所以我将不得不凭记忆工作。
这看起来像是 UTF-8 与 UTF-16 的问题,但最多可以使用五个字符集:执行 POST 的代码中使用的字符集、字符集运行代理程序的 JVM 的字符集、Domino 服务器代码的字符集、NSF 的字符集——它始终是 LMBCS,以及 Domino 服务器主机的字符集 OS。
如果我没记错的话,REQUEST_CONTENT 被视为原始数据,而不是字符数据。为了正确处理,您必须自己处理 REQUEST_CONTENT 的转换。
用于在 Java 代理中保存数据的 Notes API 调用将自动从 Unicode 转换为 LMBCS,反之亦然,但这仅在 Java 已解释时有效输入的数据流正确。我认为在大多数情况下,Domino 下的 JVM 运行 是为 UTF-16 配置的——尽管情况可能并非如此。 (我记得日本的服务器存在一些问题,其中一个起作用的字符集是 JIS 标准字符集之一,但我不记得它是否在 JVM 中。)
因此,如果我没记错的话,您需要使用 getBytes("UTF-8")
将字符串中的 REQUEST_CONTENT 作为 UTF-8 读取到字节数组中,然后使用 getBytes("UTF-8")
从字节数组中构造一个新字符串 new String(byte[] bytes, "UTF-16")
。这是假设 Then 将该字符串传递给 NotesDocument.ReplaceItemValue()
,以便 Notes API 调用应该正确解释它。
我这里可能有些细节有误。有一阵子了。我很久以前建立了一个数据库,它显示了多年前所有 Unicode 字符的 LMBCS、UTF-8 和 UTF-16 值。如果您可以深入了解字节值,它可以成为一个有用的工具来查看这样的数据并弄清楚到底发生了什么。是 downloadable from OpenNTF here。在这种情况下,我记得写过获取字节数组并将其转换为十六进制并将其写入 NotesItem 的代码,这样我就可以准确地看到传入的内容并将其与数据库条目进行比较。
而且,是的,根据评论,如果让双方的 XML 工具处理字符集问题和编码会更好——但这并不总是万无一失的。您正在向流程中添加另一层字符集!你必须做对。如果目标是在 NotesItems 中存储数据,您仍然必须确保 server-side XML 工具解码为正确的字符集,这可能不是默认的。
看到这里我的心都碎了。我也是刚刚走过这个地狱,找到了老建议,但是...我就是无法写入磁盘来解决这种小事。
Item item = agentContext.getDocumentContext().getFirstItem("REQUEST_CONTENT");
byte[] bytes = item.getValueCustomDataBytes("");
String content= new String (bytes, Charset.forName("UTF-8"));
根据 OP 的评论进行编辑:关于这个主题有一个旧的 post:
http://www-10.lotus.com/ldd/nd85forum.nsf/DateAllFlatWeb/ab8a5283e5a4acd485257baa006bbef2?OpenDocument(OP 用于解决方法的同一线程)
这家伙声称,当他使用特定的 http header 时,该方法失败了。
现在他正在使用 8.5 并使用 LS。在我的例子中,我不能通过发送额外的 header (或在字符串参数的函数中)
来让它失败
我是如何学会停止担心并爱上 Notes/Domino:
对于它的价值 getValueCustomDataBytes()
仅适用于非常短的有效载荷。取决于内容!以重音字符(例如“é”)开始您的文本会增加它仍然可以使用的长度......但无论我尝试什么,我都无法超过 195 个字符。我很惊讶吗?在使用 Notes 这么多年之后,我必须承认我仍然...
嗯,诚然,它一开始就不应该起作用,因为它被记录为仅用于用户定义的数据字段。
终于
使用 IBM 的 icu4j 和 icu4j-charset 包 - 将它们放在 jvm/lib/ext 中。那么代码就变成了:
byte[] bytes = item.getText().getBytes(CharsetICU.forNameICU("LMBCS"));
String content= new String (bytes, Charset.forName("UTF-8"));
是的,需要 java.policy 中的许可:
permission java.lang.RuntimePermission "charsetProvider";
这比通过文件系统更好吗?不知道。但是看起来有点干净。
我在 Lotus-Domino 中有一个 Java WebAgent,它通过 OpenURL 命令 (https://link.com/db.nsf/agentName?openagent) 运行。创建此代理是为了接收包含 XML 内容的 POST。在解析或保存 (XML) 内容之前,webagent 将内容保存到内存中的文档中:
For an agent run from a browser with the OpenAgent URL command, the in-memory document is a new document containing an item for each CGI (Common Gateway Interface) variable supported by Domino®. Each item has the name and current value of a supported CGI variable. (No design work on your part is needed; the CGI variables are available automatically.) https://www.ibm.com/support/knowledgecenter/en/SSVRGU_9.0.1/basic/H_DOCUMENTCONTEXT_PROPERTY_JAVA.html
POST 的内容将(由 Lotus)保存到 request_content
字段中。当接收到带有此字符的内容时:é,如:
<Name xml:lang="en">tést</Name>
Lotus 将 é 更改为 ?®。这也是我在读取文档属性中的 request_content
字段时看到的。是否可以在 Lotus 中将 é 保存为 é 而不是 a: ?®?
解决方法:
我修复它的方法是通过 post:
Link which help me solve this problem
但在Java中的解决方案:
/****** INITIALIZATION ******/
session = getSession();
AgentContext agentContext = session.getAgentContext();
Stream stream = session.createStream();
stream.open("C:\Temp\test.txt", "LMBCS");
stream.writeText(agentContext.getDocumentContext().getItemValueString("REQUEST_CONTENT"));
stream.close();
stream.open("C:\Temp\test.txt", "UTF-8");
String Content = stream.readText();
stream.close();
System.out.println("Content: " + Content);
我以前处理过这个问题,但我无法再访问代码,所以我将不得不凭记忆工作。
这看起来像是 UTF-8 与 UTF-16 的问题,但最多可以使用五个字符集:执行 POST 的代码中使用的字符集、字符集运行代理程序的 JVM 的字符集、Domino 服务器代码的字符集、NSF 的字符集——它始终是 LMBCS,以及 Domino 服务器主机的字符集 OS。
如果我没记错的话,REQUEST_CONTENT 被视为原始数据,而不是字符数据。为了正确处理,您必须自己处理 REQUEST_CONTENT 的转换。
用于在 Java 代理中保存数据的 Notes API 调用将自动从 Unicode 转换为 LMBCS,反之亦然,但这仅在 Java 已解释时有效输入的数据流正确。我认为在大多数情况下,Domino 下的 JVM 运行 是为 UTF-16 配置的——尽管情况可能并非如此。 (我记得日本的服务器存在一些问题,其中一个起作用的字符集是 JIS 标准字符集之一,但我不记得它是否在 JVM 中。)
因此,如果我没记错的话,您需要使用 getBytes("UTF-8")
将字符串中的 REQUEST_CONTENT 作为 UTF-8 读取到字节数组中,然后使用 getBytes("UTF-8")
从字节数组中构造一个新字符串 new String(byte[] bytes, "UTF-16")
。这是假设 Then 将该字符串传递给 NotesDocument.ReplaceItemValue()
,以便 Notes API 调用应该正确解释它。
我这里可能有些细节有误。有一阵子了。我很久以前建立了一个数据库,它显示了多年前所有 Unicode 字符的 LMBCS、UTF-8 和 UTF-16 值。如果您可以深入了解字节值,它可以成为一个有用的工具来查看这样的数据并弄清楚到底发生了什么。是 downloadable from OpenNTF here。在这种情况下,我记得写过获取字节数组并将其转换为十六进制并将其写入 NotesItem 的代码,这样我就可以准确地看到传入的内容并将其与数据库条目进行比较。
而且,是的,根据评论,如果让双方的 XML 工具处理字符集问题和编码会更好——但这并不总是万无一失的。您正在向流程中添加另一层字符集!你必须做对。如果目标是在 NotesItems 中存储数据,您仍然必须确保 server-side XML 工具解码为正确的字符集,这可能不是默认的。
看到这里我的心都碎了。我也是刚刚走过这个地狱,找到了老建议,但是...我就是无法写入磁盘来解决这种小事。
Item item = agentContext.getDocumentContext().getFirstItem("REQUEST_CONTENT");
byte[] bytes = item.getValueCustomDataBytes("");
String content= new String (bytes, Charset.forName("UTF-8"));
根据 OP 的评论进行编辑:关于这个主题有一个旧的 post: http://www-10.lotus.com/ldd/nd85forum.nsf/DateAllFlatWeb/ab8a5283e5a4acd485257baa006bbef2?OpenDocument(OP 用于解决方法的同一线程)
这家伙声称,当他使用特定的 http header 时,该方法失败了。 现在他正在使用 8.5 并使用 LS。在我的例子中,我不能通过发送额外的 header (或在字符串参数的函数中)
来让它失败我是如何学会停止担心并爱上 Notes/Domino:
对于它的价值 getValueCustomDataBytes()
仅适用于非常短的有效载荷。取决于内容!以重音字符(例如“é”)开始您的文本会增加它仍然可以使用的长度......但无论我尝试什么,我都无法超过 195 个字符。我很惊讶吗?在使用 Notes 这么多年之后,我必须承认我仍然...
嗯,诚然,它一开始就不应该起作用,因为它被记录为仅用于用户定义的数据字段。
终于 使用 IBM 的 icu4j 和 icu4j-charset 包 - 将它们放在 jvm/lib/ext 中。那么代码就变成了:
byte[] bytes = item.getText().getBytes(CharsetICU.forNameICU("LMBCS"));
String content= new String (bytes, Charset.forName("UTF-8"));
是的,需要 java.policy 中的许可:
permission java.lang.RuntimePermission "charsetProvider";
这比通过文件系统更好吗?不知道。但是看起来有点干净。