Java 当字符集为UTF-8时,使用OutputStream发送特殊字符时出错

Java 当字符集为UTF-8时,使用OutputStream发送特殊字符时出错,java,character-encoding,Java,Character Encoding,我正在使用HttpServer创建一个简单的服务。当我使用没有特殊字符的字符串时,服务可以正常工作 public static void main (String arg []) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(serverPort), 0); server.createContext("/notification", new MyHa

我正在使用HttpServer创建一个简单的服务。当我使用没有特殊字符的字符串时,服务可以正常工作

public static void main (String arg []) throws Exception {
    HttpServer server = HttpServer.create(new InetSocketAddress(serverPort), 0);
    server.createContext("/notification", new MyHandler());
    server.setExecutor(null); // creates a default executor
    server.start();
}

static class MyHandler implements HttpHandler {
    public void handle(HttpExchange t) throws IOException {
        String response;

        response = "with special characters éáã "; // it doesn't work
        response = "without special characters"; // it works!

        String encoding = "UTF-8";

        System.out.println(response);

        t.getResponseHeaders().set("Content-Type", "application/json; charset=" + encoding);

        t.sendResponseHeaders(200, response.length());
        byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
        OutputStream os = t.getResponseBody();
        os.write(bytes);
        os.flush();

        os.close();
    }
}
当我的UTF-8字符串具有特殊字符时,它将返回以下错误:

java.io.IOException:太多字节无法写入流 在sun.net.httpserver.FixedLengthOutputStream.write(FixedLengthOutputStream.java:76)上 在java.io.FilterOutputStream.write(FilterOutputStream.java:97) 位于sun.net.httpserver.PlaceholderOutputStream.write(ExchangeImpl.java:439) 位于InternalServer$MyHandler.handle(InternalServer.java:86) 位于com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) 位于sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83) 位于com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82) 位于sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675) 位于com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) 位于sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:647) 位于sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:158) 位于sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:431) 位于sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:396) 在java.lang.Thread.run(Thread.java:748)

这里是问题所在

 t.sendResponseHeaders(200, response.length());
sendResponseHeaders
的第二个参数必须是要发送的内容的确切大小,以字节为单位。但是您正在以字符形式传递字符串的长度

在UTF-8中,任何大于U+0080的字符都将被编码为2个或更多字节。第二个示例字符串包含大于U+0080的字符,因此在UTF-8中编码时,字符计数和字节计数是不同的。您将在响应标题中设置不正确的内容长度

看起来,HttpExchange提供的输出流正在检查您发送的字节数是否没有超过在响应头中设置的字节数。(这将违反HTTP协议。)

解决方案:

 ...
 byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
 t.sendResponseHeaders(200, bytes.length);
 ...
也可以将
0
作为内容长度传递。这将导致使用发送正文。

问题出在这里

 t.sendResponseHeaders(200, response.length());
sendResponseHeaders
的第二个参数必须是要发送的内容的确切大小,以字节为单位。但是您正在以字符形式传递字符串的长度

在UTF-8中,任何大于U+0080的字符都将被编码为2个或更多字节。第二个示例字符串包含大于U+0080的字符,因此在UTF-8中编码时,字符计数和字节计数是不同的。您将在响应标题中设置不正确的内容长度

看起来,HttpExchange提供的输出流正在检查您发送的字节数是否没有超过在响应头中设置的字节数。(这将违反HTTP协议。)

解决方案:

 ...
 byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
 t.sendResponseHeaders(200, bytes.length);
 ...
也可以将
0
作为内容长度传递。这将导致使用发送正文