读取InputStream时忽略编码

时间:2014-10-02 09:40:01

标签: java http encoding inputstreamreader

我在向IIS服务器发出HTTP请求的Java应用程序中遇到了一些编码问题。

迭代URLConnection对象的标题我可以看到以下(相关)标题:

Transfer-Encoding: [chunked]
Content-Encoding: [utf-8]
Content-Type: [text/html; charset=utf-8]

URLConnection.getContentEncoding()方法返回utf-8作为文档编码。

这是我的HTTP请求和流读取的方式:

OutputStreamWriter sw = null;
BufferedReader br = null;
char[] buffer = null;
URL url;
url = new URL(this.URL);
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
sw = new OutputStreamWriter(connection.getOutputStream());
sw.write(postData);
sw.flush();
br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF8"));
StringBuilder totalResponse = new StringBuilder();
String line;

while((line = br.readLine()) != null) {
    totalResponse.append(line);
}
buffer = totalResponse.toString().toCharArray();
if (sw != null)
    sw.close();

if (br != null)
    br.close();

return buffer;

然而,服务器“ÃÃÃção”发送的以下字符串被客户端收到“ o”。

我做错了什么?

4 个答案:

答案 0 :(得分:1)

根据您的评论,您尝试从IIS服务器接收FIX消息,FIX使用ASCII。只有一小部分标签支持其他编码,它们必须以特殊方式处理(标准FIX规范中的非ASCII标签为349,351,353,355,357,359,361,363,365)。如果存在这样的标记,您将获得带有指定编码的值的标记347(例如UTF-8),然后每个标记前面都会有一个标记,为您提供即将到来的编码值的长度(对于标记349,你将永远得到348第一个整数值)

在您的情况下,看起来服务器正在以某种其他编码发送自定义标记10411(10xxx范围)。按照惯例,前面的标记10410应该给出10411中值的长度,但它包含“0000”,这可能有其他含义。

请注意,虽然FIX消息非常易读,但它们仍应被视为二进制数据。标签和值大多是ASCII字符,但是分隔符(SOH)是0x01,如上所述,某些标签可以用另一种编码进行编码。 IIS服务应该真正将数据作为application/octet-stream返回,以便正确接收。试图将其作为text/html返回是一个问题:)。

答案 1 :(得分:0)

如果服务器确实发送了内容编码" UTF-8"然后它非常混淆。见http://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231.html#header.content-encoding

答案 2 :(得分:0)

为了良好的秩序,可以进行一些修正。

    URLConnection connection = url.openConnection();
    connection.setDoOutput(true);
    connection.connect();
    try (Writer sw = new OutputStreamWriter(connection.getOutputStream(),
                StandardCharsets.UTF_8)) {
        sw.write(postData);
        sw.flush();

        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(connection.getInputStream(),
                StandardCharsets.UTF_8))) {
            StringBuilder totalResponse = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                totalResponse.append(line).append("\r\n");
            }
            return totalResponse.toString().toCharArray();
        } // Close br.
    } // Close sw.

也许:

postData =  ... + "Accept-Charset: utf-8\r\n" + ...;

收到totalResponse.toString()您应该正确阅读。

但是当再次显示时,String / char再次转换为字节,那里编码失败。例如System.out.println不会这样做,因为可能使用了Windows编码。

您可以通过转储字节来测试字符串:

String s = totalResponse.toString();
Logger.getLogger(getClass().getName()).log(Level.INFORMATION, "{0}",
    Arrays.toString(s.getBytes(StandardCharsets.UTF_8)));

在极少数情况下,字体不会包含特殊字符。

答案 3 :(得分:0)

您可以尝试将流作为请求属性的一部分,然后在客户端打印出来。如果遇到任何编码问题,将收到请求属性