2.2.0 版本 apollo中,值文本修改中,历史或者新的参数有\n 的值,会转换成换行符
重现该行为的步骤 在 apollo文本中输入key,answer = (?:。\n\n|。 \n|。\n|\n\n|\n|。|\n) value转换成 (?:。
|。 |。 |
|
|。|
)
2.2.0 版本 apollo中,值文本修改中,历史或者新的参数有\n 的值,会转换成换行符。 历史版本也存在这种情况。
在 Apollo 2.2.0 版本中,值文本修改中将历史或新参数中的 "\n" 转换为换行符的行为是在 PropertyResolver 类的 handleNormalLine 方法中实现的。具体代码如下:
String newValue = kv[1].replace("\\n", "\n"); //handle user input \n
这行代码将键值对中值部分的字符串字面量 "\n" 替换为实际的换行符。这是为了处理用户输入中 "\n" 代表换行的情况。
要重现这种行为,可以创建一个包含键值对的配置文本,其中值包含字符串 "\n"。当 PropertyResolver 处理这些文本时,它们将被转换为实际的换行符。
例如:
String configText = "key1=value1\\nvalue2";
当调用 resolve 方法处理这个 configText 时,key1 的值将被转换为:
value1
value2
这种行为在历史版本中也存在 [1]。
To continue talking to Dosu, mention @dosu.
Help Dosu learn! Give it feedback: Great Response | Irrelevant Answer | Incorrect Sources | Too Verbose | Hallucination | Other
可以在 apollo demo 站点( http://81.68.181.139/ )重现该问题吗?我刚试了下没遇到这个问题
@nobodyiam 也会有这个问题, http://81.68.181.139/config.html?#/appid=01test 要是properties的格式
可以在 apollo demo 站点( http://81.68.181.139/ )重现该问题吗?我刚试了下没遇到这个问题
@nobodyiam 老哥看看http://81.68.181.139/config.html?#/appid=01test的 application namespace,我没提交
@jesusys 我这边仍然没法重现,看历史提交记录,你提交的值本身没有 \n,而最近的一条是我提交的有 \n,是否你的编辑器/浏览器做了转义?
先在文本中输入answer = (?:。\n\n|。 \n|。\n|\n\n|\n|。|\n),点击表格,就会看到输入的和表格中显示的不同了
直接找表格中输入answer = (?:。\n\n|。 \n|。\n|\n\n|\n|。|\n),就是正确的。
一般生产中有一次录入很多配置的话,会选择文本中粘贴配置,这样就会导致,原来answer = (?:。\n\n|。 \n|。\n|\n\n|\n|。|\n)的数据变了。 @nobodyiam
复现了,直接在表格那里新增配置项不会出现问题,但是在文本模式新增就会出现问题,甚至会让原本正常的表格配置也出问题。
可能是文本模式的某一步转换出现了问题。
@spaceluke 在比较老的 0.8 版本的 apollo 也同样有这个情况。是不是可以打补丁或者,升级新版本优化。
晚上排查一下看看
主要原因是 后端 portal 的PropertyResolver 的 handleNormalLine 方法有一步把用户输入的\n转成字符串转成真正的换行符
private void handleNormalLine(Long namespaceId, Map<String, ItemDTO> keyMapOldItem, String newItem,
int lineCounter, ItemChangeSets changeSets) {
String[] kv = parseKeyValueFromItem(newItem);
if (kv == null) {
throw new BadRequestException("line:" + lineCounter + " key value must separate by '='");
}
String newKey = kv[0];
String newValue = kv[1].replace("\\n", "\n"); //handle user input \n
ItemDTO oldItem = keyMapOldItem.get(newKey);
//new item
if (oldItem == null) {
changeSets.addCreateItem(buildNormalItem(0L, namespaceId, newKey, newValue, "", lineCounter));
//update item
} else if (!StringUtils.equals(newValue, oldItem.getValue()) || lineCounter != oldItem.getLineNum()) {
changeSets.addUpdateItem(buildNormalItem(oldItem.getId(), namespaceId, newKey, newValue, oldItem.getComment(), lineCounter));
}
keyMapOldItem.remove(newKey);
}
@nobodyiam 这边原本这样设计的初衷是什么?
因为是对用户的输入和输出进行不对等的修改了,是否可以把这个逻辑去掉,让用户输入什么就能获得什么输出我认为会比较好。👀
最快复现方式 for developer:
在com.ctrip.framework.apollo.portal.component.txtresolver.PropertyResolverTest 中添加下面的测试方法并运行
@Test
public void testUserInputNewLine() {
String configText = "answer = (?:。\\n\\n|。 \\n|。\\n|\\n\\n|\\n|。|\\n)\na=b";
System.out.println(configText);
ItemChangeSets changeSets = resolver.resolve(1, configText, null);
List<ItemDTO> createItems = changeSets.getCreateItems();
createItems.forEach(itemDTO -> {
System.out.println(itemDTO.getKey() + " " + itemDTO.getValue());
});
}
看了下是非常早期的一个 commit 实现的 - https://github.com/apolloconfig/apollo/commit/d250cd20732b5b90aa330a7d855dcc2b8e37f861
看了下应该是为了支持用户在文本模式时输入换行符,所以加入了把 \n 替换为换行符的逻辑。考虑到这个逻辑已经存在很久了,不太建议直接修改这个逻辑。
@nobodyiam @spaceluke 两位也帮忙看看有没有其他办法可以解决,\n是有不合理的地方?
@nobodyiam @spaceluke 两位也帮忙看看有没有其他办法可以解决,\n是有不合理的地方?
\n 从原本的两个字节'\' + 'n'被apollo server端转成一个字节的 '\n' 了,解决方案可以是在client端拿到配置项的Value之后,做一层转换 把 '\n' 替换成两个字节 '\' + 'n'