Java SAXParser解析BGG XML在AWS EC2与Windows环境差异排查
BGG XML API2 SAX解析跨环境UTF-8错误问题求助
错误日志
Failed to parse url https://www.boardgamegeek.com/xmlapi2/thing?id=303215&stats=1 org.xml.sax.SAXParseException; systemId: https://boardgamegeek.com/xmlapi2/thing?id=303215&stats=1; lineNumber: 1; columnNumber: 1; Invalid byte 1 of 1-byte UTF-8 sequence. com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.
异常特殊表现
- 代码自2024年6月后未改动,此前运行完全正常;
- 95%以上游戏ID解析正常,仅少数出现失败;
- 仅游戏数据处理偶发失败,其他BGG数据解析无异常;
- 解析失败的游戏ID随运行环境变化:ID303215在本地Windows环境正常,但在AWS EC2(Amazon Linux 2023+Corretto21、Amazon Linux2+Corretto17)生产环境报错;ID413908则相反;
- 出错的Handler仅检查qName和属性,未使用StringBuilder或DefaultHandler的
characters方法; - 部分URL多次报错后会自动恢复解析成功。
所有环境下的错误均为Invalid byte 1 of 1-byte UTF-8 sequence。
已尝试的排查方案
- 使用在线验证工具检查URL对应的XML;
- 修改代码指定编码(UTF-8、ISO-8859-1、Windows-1252、UTF-16),替换原自动检测编码逻辑:
try { InputSource inputSource = new InputSource(url); inputSource.setEncoding("UTF-8"); // 尝试过ISO-8859-1, Windows-1252, 和 UTF-16. parser.parse(inputSource, dh); // 原代码为parser.parse(url, dh); } catch (Exception e) { System.out.println("Failed to parse url " + url); System.out.println(e); if (e instanceof SAXException) { // 新增该判断 System.out.println(e.getCause()); } }
目前仍在排查字节顺序标记(Byte Order Mark)等相关问题,但未找到跨环境差异的原因。附Handler代码片段:
@Override public void startDocument() { primaryGameName = ""; averageWeight = DBQueries.MAX_COMPLEXITY; yearPublished = -1; publisherMinAge = -1; [...] @Override public void startElement(String uri, String localName, String qName, Attributes attributes) { if ("name".equals(qName)) { if ("primary".equals(attributes.getValue("type"))) { if (attributeHasValue(attributes, "value")) { primaryGameName = attributes.getValue("value"); } else { System.out.println("WARNING: game's name not found! " + attributes); } } } else if ("averageweight".equals(qName)) { if (attributeHasValue(attributes, "value")) { averageWeight = Float.parseFloat(attributes.getValue("value")); } [...] @Override public void endElement(String uri, String localName, String qName) { if ("poll".equals(qName)) { isPollingPlayerCounts = false; isPollingPlayerAge = false; [...] private boolean attributeHasValue(Attributes attributes, String valueName) { return !(null == attributes.getValue(valueName) || attributes.getValue(valueName).isEmpty()); }
现寻求该跨环境解析差异问题的解决方案。
内容的提问来源于stack exchange,提问作者Philip H
相关产品推荐
相关产品推荐

