使用HttpURLConnection发送UTF-8字符串

20

到目前为止,我一直使用以下代码片段来发送和接收JSON字符串:

static private String sendJson(String json,String url){
    HttpClient httpClient = new DefaultHttpClient();
    String responseString = "";
    try {
        HttpPost request = new HttpPost(url);
        StringEntity params =new StringEntity(json, "UTF-8");
        request.addHeader("content-type", "application/json");
        request.setEntity(params);
        HttpResponse response = httpClient.execute(request);
        HttpEntity entity = response.getEntity();
        responseString = EntityUtils.toString(entity, "UTF-8");

    }catch (Exception ex) {
        ex.printStackTrace();
        // handle exception here
    } finally {
        httpClient.getConnectionManager().shutdown();
    }
    return responseString;
}

即使JSON字符串包含UTF-8字符,上述代码仍能完美运行,一切都正常。

由于几个原因,我必须改变发送HTTP POST请求的方式,并使用HttpURLConnection而不是Apache的HttpClient。以下是我的代码:

static private String sendJson(String json,String url){
    String responseString = "";
    try {
        URL m_url = new URL(url);
        HttpURLConnection conn = (HttpURLConnection)m_url.openConnection();
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("content-type", "application/json");
        DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream());
        outputStream.writeBytes(json);
        outputStream.flush();
        outputStream.close();

        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line+"\n");
        }
        br.close();
        responseString = sb.toString();
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return responseString;
}

这段代码对于普通的英文字符可以正常工作,但是似乎无法支持json字符串中的UTF-8字符,因为每次都会失败。(当向服务器发送json时,服务器会崩溃并说utf8无法解码某个字节,但是当从服务器接收utf8 json时,我认为它可以正常工作,因为我能够查看特殊字符)。

服务器完全没有改变,以前的代码也可以正常工作,所以问题100%是在这个新的代码片段上。

有什么办法可以修复json字符串发送,使其支持UTF 8?谢谢

3个回答

41

我认为问题出在这部分:

DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream());
outputStream.writeBytes(json);
outputStream.flush();
outputStream.close();

不要这样做,你需要将json编码为UTF-8,并发送代表UTF-8编码的字节。

尝试使用以下代码:

Charset.forName("UTF-8").encode(json)

参见:

Charset.encode

使用更简单的方法是例如使用包装OutputStreamWriterBufferedWriterOutputStreamWriter知道自己的编码方式,因此将为您完成工作(对 json 字符串的编码工作)。

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8"));
bw.write(json);
bw.flush();
bw.close();

7

在将字符串写入输出流(字节)时,您需要指定编码以进行转换。其中一种方法是将输出流包装在OutputStreamWriter中,该编码将使用UTF-8字符集。

        conn.setRequestProperty("content-type", "application/json;  charset=utf-8");
        Writer writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8"));
        writer.write(json);
        writer.close();
close()方法也可以替代flush()方法。

另一种选择是,如peter.petrov所提到的,可以先将String转换为字节数组(在内存中),然后将该字节数组输出到输出流。

为了在服务器端更加明显,您可以在content-type头部中传递使用的字符集 ("content-type", "application/json; charset=utf-8")。


4

StringEntity 使用 Charset 来确保编码正确。它会进行以下操作:

byte[] content = s.getBytes(charset);

在几乎不改变你的代码的情况下,你可以这样写:

outputStream.write(json.getBytes("UTF-8"));

针对你的读取操作,使用BufferedReaderreadLine没有任何意义,除了规范化行尾。这种方法比其他方法慢得多,因为它需要逐个字节地读取。

EntityUtils主要做的就是这个:

    Reader reader = new InputStreamReader(conn.getInputStream(), "UTF-8");
    StringBuilder buffer = new StringBuilder();
    char[] tmp = new char[1024];
    int l;
    while((l = reader.read(tmp)) != -1) {
        buffer.append(tmp, 0, l);
    }
    responseString = buffer.toString();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接