hsurich

hsurich

coder
github
telegram
x
email
steam

在JDK中,當使用DataOutputStream.writeBytes方法傳遞中文時,會出現亂碼的問題。

java 项目中有段封装的发送 post 请求方法

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;

public class FormDataPostRequest {

    public static String sendPostFormData(String url, Map<String, String> headerParams, String text) {
        String result = ""; // 返回的结果
        BufferedReader in = null; // 读取响应输入流

        try {
            //创建连接
            URL apiUrl = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) apiUrl.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + "*****"); // 设置boundary
            if (headerParams != null) {
                for (Entry<String, String> entry : headerParams.entrySet()) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }
            connection.connect();

            // 发送POST请求,包含字符串参数
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            // 添加字符串参数
            out.writeBytes("--*****\r\n");
            out.writeBytes("Content-Disposition: form-data; name=\"text\"\r\n\r\n");
            out.write(text.getBytes("UTF-8"));
            out.writeBytes("\r\n");
            out.writeBytes("--*****--\r\n");
            out.flush();
            out.close();

            // 读取响应
            // 定义BufferedReader输入流来读取URL的响应,并设置编码方式
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;
            // 读取返回的内容
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Http请求方法内部问题");
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }
}

原本使用没有什麼問題,後續在使用過程中,發現當參數的值為中文時,接收方會收到亂碼,查看程式碼發現問題出現這一行。

out.writeBytes(text + "\r\n");

查看writeBytes原始碼

/**
 * Writes out the string to the underlying output stream as a
 * sequence of bytes. Each character in the string is written out, in
 * sequence, by discarding its high eight bits. If no exception is
 * thrown, the counter {@code written} is incremented by the
 * length of {@code s}.
 *
 * @param      s   a string of bytes to be written.
 * @throws     IOException  if an I/O error occurs.
 * @see        java.io.FilterOutputStream#out
 */
public final void writeBytes(String s) throws IOException {
    int len = s.length();
    for (int i = 0 ; i < len ; i++) {
        out.write((byte)s.charAt(i));
    }
    incCount(len);
}

發現字串 s 的每個字元都會被強制轉換成 byte 型別,byte 型別是 8 位元的,而中文的 char 是 16 位元,所以當字元為中文時,會被截斷,導致亂碼,可以加一些日誌,看一下轉換後的 byte 陣列。

public final void writeBytes(String s) throws IOException {
    int len = s.length();
    for (int i = 0 ; i < len ; i++) {
        char c = s.charAt(i);
        byte b = (byte) c;
        System.out.println("字元:" + c + " 轉換後的byte陣列:" + b);
        out.write(b);
    }
    incCount(len);
}

最終能看到中文字元被強轉後,會丟失 8 位元,導致亂碼。因此解決方案將字串轉換成 byte 陣列,然後寫入輸出流。

// 發送POST請求,包含字串參數
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
// 添加字串參數
out.writeBytes("--*****\r\n");
out.writeBytes("Content-Disposition: form-data; name=\"text\"\r\n\r\n");
out.write(text.getBytes("UTF-8"));
out.writeBytes("\r\n");
out.writeBytes("--*****--\r\n");
out.flush();
out.close();
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。