Java 读取InputStream时忽略编码

Java 读取InputStream时忽略编码,java,http,encoding,inputstreamreader,Java,Http,Encoding,Inputstreamreader,我在向IIS服务器发出HTTP请求的Java应用程序中遇到一些编码问题 迭代URLConnection对象的标题,我可以看到以下(相关)标题: URLConnection.getContentEncoding()方法返回utf-8作为文档编码 这就是我的HTTP请求和流读取的方式: OutputStreamWriter sw = null; BufferedReader br = null; char[] buffer = null; URL url; url = new URL(this.UR

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

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

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”


我做错了什么?

如果服务器真的发送了一个“UTF-8”的内容编码,那么它是非常混乱的。请参见

了解良好的顺序和一些更正

    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()
时,您应该已经正确读取了所有内容

但当再次显示时,字符串/字符再次转换为字节,编码失败。例如,System.out.println可能不会使用Windows编码

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

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

在某些罕见的情况下,字体将不包含特殊字符。

根据您的评论,您试图从IIS服务器接收修复消息,修复使用ASCII。只有一小部分标签支持其他编码,必须以特殊方式处理(标准FIX规范中的非ASCII标签为349351355335537359361363365)。如果存在这样的标记,您将得到一个标记347,其值指定编码(例如UTF-8),然后每个标记前面都会有一个标记,该标记给出未来编码值的长度(对于标记349,您将始终首先得到348,其值为整数值)

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


请注意,尽管修复消息可读性很强,但它们仍应被视为二进制数据。标记和值大多是ASCII字符,但分隔符(SOH)是0x01,如上所述,某些标记可以使用另一种编码进行编码。IIS服务应该以
application/octet-stream
的形式返回数据,以便正确地接收数据。试图将其作为
text/html
返回会带来麻烦:)。

您可以尝试将流作为请求属性的一部分,然后在客户端打印出来。请求属性将按原样接收,没有任何编码问题

我认为它必须是
UTF-8
而不是
UTF8
谢谢@Tirath的回复。作为InputStreamReader构造函数的参数,我已将UTF8更改为UTF-8,但结果是相同的。您确定您的内容实际上是UTF-8编码的吗?标题可能是谎言。您还尝试过调试
totalResponse.toString()
?如果这等于
“ÃÃÃção”
,那么在
char[]
上操作时,您的问题可能会更进一步……谢谢@Mena,我如何实际验证内容编码。使用:
byte[]foo=String.valueOf(totalResponse.toString()).getBytes();System.out.println(新字符串(foo,“utf-8”)
给出了完全相同的结果。可能不相关,但在创建
OutputStreamWriter
时,您还应该设置显式编码-此时您正在以平台上的默认编码发送post数据,这可能不是服务器所期望的。内容编码标签是我的错误。现在不包括在内。谢谢你的回复。结果和以前一样。对于以下字符串:
INFO:8=FIX.4.29=3335=DRCFG10410=000010411=�����o10=000\0
我得到以下字节:
信息:[56,61,70,73,88,46,52,46,50,1,57,61,51,1,51,53,61,68,82,67,70,71,1,49,48,52,49,48,48,48,48,48,52,49,49,61,17,65,67,17,65,67,65,67,111,1,49,48,48,48,48,48,48,48,52,49,49,49,49,49,61,67,65,67,67,67,67,65,65,65,65,65,65,65,65,65,68,11,11,11,11,48,11,52]
如果你看411=��, 也就是说48+4(4),48+1(1),48+1(1),61(=)可以看到四个相同的多字节序列的重复。实际上,
U+FFFD
,Unicode替换字符。由于UTF-8可以代表所有,在Unicode的早期转换中,比如说UTF-8到有限编码,进行了此转换。肯定是在IIS端,除非数据来自客户端的往返。因此,如果我没有正确理解您的意思,您是说IIS正在以其他字符集发送数据,并在过程中进行转换?IIS在某些时候错误地转换为非UTF-8(引入替换字符),最后以UTF-8交付。作为健全检查,可能在浏览器中查询相同的内容。再次感谢!该服务由几个组件(Objective、C#、JS)使用,编码中唯一存在问题的是JAVA中的这个组件。在服务器端,我可以看到消息被正确发送。对发生的事情还有什么想法吗?你是对的。这是一个基于FIX的自定义消息协议。将
内容类型
设置为
应用程序/octet流
具有相同的结果(�����o代表ÃÃÃço)。谢谢你的回复。
String s = totalResponse.toString();
Logger.getLogger(getClass().getName()).log(Level.INFORMATION, "{0}",
    Arrays.toString(s.getBytes(StandardCharsets.UTF_8)));