仕様的には
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);