ASi

How to send multipart/form-data

仕様的には
https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
https://tools.ietf.org/html/rfc7578
https://www.ietf.org/rfc/rfc2047.txt

1つの field を1つの partとして含む bodyを送る。
ASCII外の文字を field の名前に使う場合は RFC2047 に従ってエンコードする必要がある。
巷には =?UTF-8?B? の B が小文字の例もあったりするが、正しくは大文字。実際 tomcat は小文字では受け付けない。

StringBuilder で扱っているが UTF-8 なので辻褄が合う。他の文字コードを使う場合は考慮が必要。
厳密には boundary が filed name/value と被らないよう検査も事前に必要。

tomcat8 では Content-Disposition に filename が有ると request parameter として扱わず getPart で取れるようになる。ファイルの送信ではこれを使う。逆を言うと filename を付けないと form のテキストフィールドの扱いになる。

    HttpURLConnection con = (HttpURLConnection) url.openConnection();

    String boundary = "---------------------------" + System.currentTimeMillis();
    con.setRequestProperty("Content-Type",
            "multipart/form-data; boundary=" + boundary);

    StringBuilder body = new StringBuilder();
    Encoder base64 = Base64.getMimeEncoder(); // java.util.Base64
    
    for(Map.Entry<String, String> entry : formData.entrySet()){
        body.append("--").append(boundary).append("\r\n")
        .append("Content-Disposition: form-data; name=\"=?UTF-8?B?")
            .append(base64.encodeToString(entry.getKey().getBytes(UTF_8))).append("?=\"\r\n")
        .append("Content-Type: text/plain; charset=UTF-8\r\n")
        .append("\r\n")
        .append(entry.getValue()).append("\r\n");
    }
    body.append("--").append(boundary).append("--\r\n");
    
    post(body.toString(), con);