M.S.の技術メモ

HttpURLConnectionを使ってマルチパートPOST送信

HttpURLConnectionを使用してファイルと一緒にPOST送信する方法です。
そのまま汎用クラスとして使用できます。

さくらサーバーではこの方法でPOSTしてもPHP側でデータを取得できません。
動作確認ができていませんが、このままで動くはずです。

間違っている点があればご指摘いただければと思います。

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import android.annotation.SuppressLint;
import android.os.Build;
import android.webkit.MimeTypeMap;

public class PostTask {
	private final static String TWO_HYPHEN = "--";
	private final static String EOL = "\r\n";
	private final static String BOURDARY = String.format("%x", new Random().hashCode());
	private final static String CHARSET = "UTF-8";

	@SuppressLint("DefaultLocale")
	public String post(String requestUrl, HashMap<String, String> postData) {
		String result = "";

		// 送信するコンテンツを成形する
		StringBuilder contentsBuilder = new StringBuilder();
		String closingContents = "";
		int iContentsLength = 0;
		String fileTagName = "";
		String filePath = "";
		File file = null;
		FileInputStream fis = null;

		for (Map.Entry<String, String> data : postData.entrySet()) {
			String key = data.getKey();
			String val = data.getValue();

			// ファイル以外
			if (!new File(val).isFile()) {
				contentsBuilder.append(String.format("%s%s%s", TWO_HYPHEN, BOURDARY, EOL));
				contentsBuilder.append(String.format("Content-Disposition: form-data; name=\"%s\"%s", key, EOL));
				contentsBuilder.append(EOL);
				contentsBuilder.append(val);
				contentsBuilder.append(EOL);
			}
			// ファイル
			else {
				// ファイル情報を保持しておく
				fileTagName = key;
				filePath = val;
				file = new File(filePath);
			}
		}

		// ファイル情報のセット
		contentsBuilder.append(String.format("%s%s%s", TWO_HYPHEN, BOURDARY, EOL));
		contentsBuilder.append(String.format("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"%s", fileTagName, filePath, EOL));

		// ファイルがあるとき
		if (file != null) {
			// ファイルサイズの取得
			iContentsLength += file.length();

			// MIME取得
			int iExtPos = filePath.lastIndexOf(".");
			String ext = (iExtPos > 0) ? filePath.substring(iExtPos + 1) : "";
			String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.toLowerCase());

			contentsBuilder.append(String.format("Content-Type: %s%s", mime, EOL));
		}
		// ファイルがないとき
		else {
			contentsBuilder.append(String.format("Content-Type: application/octet-stream%s", EOL));
		}

		contentsBuilder.append(EOL);
		closingContents = String.format("%s%s%s%s%s", EOL, TWO_HYPHEN, BOURDARY, TWO_HYPHEN, EOL);

		// コンテンツの長さを取得
		try {
			// StringBuilderを文字列に変化してからバイト長を取得しないと
			// 実際送ったサイズと異なる場合があり、コンテンツを正しく送信できなくなる
			iContentsLength += contentsBuilder.toString().getBytes(CHARSET).length;
			iContentsLength += closingContents.getBytes(CHARSET).length;
		} catch (UnsupportedEncodingException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}


		// サーバへ接続する
		HttpURLConnection connection = null;
		DataOutputStream os = null;
		BufferedReader br = null;

		try {
			URL url = new URL(requestUrl);

			connection = (HttpURLConnection)url.openConnection();

			connection.setDoInput(true);
			connection.setDoOutput(true);

			// キャッシュを使用しない
			connection.setUseCaches(false);

			// HTTPストリーミングを有効にする
			connection.setChunkedStreamingMode(0);

			// リクエストヘッダを設定する
			// リクエストメソッドの設定
			connection.setRequestMethod("POST");

			// 持続接続を設定
			connection.setRequestProperty("Connection", "Keep-Alive");

			// ユーザエージェントの設定(必須ではない)
			connection.setRequestProperty("User-Agent", String.format("Mozilla/5.0 (Linux; U; Android %s;)", Build.VERSION.RELEASE));

			// POSTデータの形式を設定
			connection.setRequestProperty("Content-Type", String.format("multipart/form-data; boundary=%s", BOURDARY));
			// POSTデータの長さを設定
			connection.setRequestProperty("Content-Length", String.valueOf(iContentsLength));


			// データを送信する
			os = new DataOutputStream(connection.getOutputStream());
			os.writeBytes(contentsBuilder.toString());

			// ファイルの送信
			if (file != null) {
				byte buffer[] = new byte[1024];
				fis = new FileInputStream(file);

				while (fis.read(buffer, 0, buffer.length) > -1) {
					os.write(buffer, 0, buffer.length);
				}
			}

			os.writeBytes(closingContents);


			// レスポンスを受信する
			int iResponseCode = connection.getResponseCode();

			// 接続が確立したとき
			if (iResponseCode == HttpURLConnection.HTTP_OK) {
				StringBuilder resultBuilder = new StringBuilder();
				String line = "";

				br = new BufferedReader(new InputStreamReader(connection.getInputStream()));

				// レスポンスの読み込み
				while ((line = br.readLine()) != null) {
					resultBuilder.append(String.format("%s%s", line, EOL));
				}
				result = resultBuilder.toString();
			}
			// 接続が確立できなかったとき
			else {
				result = String.valueOf(iResponseCode);
			}
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 開いたら閉じる
			try {
				if (br != null) br.close();
				if (os != null) {
					os.flush();
					os.close();
				}
				if (fis != null) fis.close();
				if (connection != null) connection.disconnect();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		// 代入したレスポンスを返す
		return result;
	}
}

“HttpURLConnectionを使ってマルチパートPOST送信” への3件のフィードバック

  1. ugg neuman より:

    Howdy! This post couldn’t be written any better! Reading through this post reminds me of my good old room mate! He always kept talking about this. I will forward this post to him. Pretty sure he will have a good read. Thank you for sharing!

  2. Greetings! Very useful advice within this article! It’s the little changes that make the greatest changes. Thanks a lot for sharing!

  3. I was able to find good advice from your articles.

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*