Java 11使用UTF-8解析HttpResponse时特殊字符转为问号如何解决
Java抓取RSS特殊字符(含emoji)显示问号解决方案
问题根因
你遇到的乱码问题由以下几个错误操作导致:
- 用
BodyHandlers.ofString()接收响应时,若响应头未明确指定编码,HttpClient默认会用ISO-8859-1解码内容,UTF-8编码的emoji等特殊字符在这一步就会被转成乱码,后续无法恢复 - 你后续将已解码错误的字符串再转成UTF-8字节流的操作完全多余,反而会放大编码问题
- 部分情况下控制台默认编码不是UTF-8,也会导致正常的字符串打印出来显示问号,需要区分是字符串本身错误还是显示错误
最优修改方案
直接跳过String中转,用字节流直接交给DocumentBuilder解析,XML解析器会自动识别XML头部的编码声明,从根源避免转码问题,修改后的代码如下:
import java.nio.charset.StandardCharsets; import java.io.InputStream; ArrayList<Entry> pullRss(){ ArrayList<Entry> output = new ArrayList<>(); try{ HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://www.reddit.com/r/anysubreddit/.rss")) // 主动告知服务端优先返回UTF-8编码内容 .header("Accept-Charset", "UTF-8") .build(); // 直接获取响应字节流,不做中间字符串转码 HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder db = factory.newDocumentBuilder(); // 直接传入字节流解析,无需手动转码 Document doc = db.parse(response.body()); NodeList nList = doc.getElementsByTagName("entry"); for (int temp = 0; temp < nList.getLength(); temp++) { Node nNode = nList.item(temp); Element eElement = (Element) nNode; String user = eElement.getElementsByTagName("name").item(0).getTextContent(); String userUri = eElement.getElementsByTagName("uri").item(0).getTextContent(); String id = eElement.getElementsByTagName("id").item(0).getTextContent(); String link = eElement.getElementsByTagName("link").item(0).getAttributes().getNamedItem("href").toString(); String date = eElement.getElementsByTagName("published").item(0).getTextContent(); String title = eElement.getElementsByTagName("title").item(0).getTextContent(); output.add(new Entry(user, userUri, id, link, date, title)); } }catch (Exception e) { e.printStackTrace(); } return output; }
可选修改方案
如果你一定要用String类型接收响应内容,可明确指定解码编码为UTF-8,修改响应接收行即可:
// 明确指定UTF-8解码响应 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
注意事项
如果修改后控制台打印仍显示问号,可在JVM启动参数中添加-Dfile.encoding=UTF-8,同时将IDE的控制台编码设置为UTF-8即可解决,该问题仅为显示问题,不影响字符串本身存储的内容正确性。
内容的提问来源于stack exchange,提问作者Georodin
相关产品推荐
相关产品推荐

