[Java]署名付きURLでS3にテキストファイルアップロードする
JavaでAWSのS3に署名付きURLを使ってテキストファイルをアップロードするソースコード(覚え書き)です。
経緯など
S3にファイルを安全にアップロードする代表的な方法として、VPCエンドポイントを経由する方法があげられますが、AWS SDK S3のバージョンが古くて対応しているクラス(AmazonS3ClientBuilder)が使えない&環境起因でSDKのアップグレードも叶わず、やむを得ず署名付きURLを使うことになりました。
本記事では、コードの作成に当たって最も苦戦した、AWSから受け取った署名付きURLを使ってテキストファイルをアップロードするパートについて、自身の覚え書きも兼ねて、ソースコードを載せておきます。
ソースコード
以下、AWSより取得した署名付きURLを使ってS3にファイルをアップロードするメソッドです(import文は割愛しています)。
今回、CSVファイルのアップロードを想定した内容(主に、コメント)にしています。
/**
* CSVファイルをS3へアップロードする
*
*
* @param strPresignedUrl 署名付きURL
* @param filePath ローカル上で作成されたファイルのパス
* @param fileName アップロードするファイル名(上位ディレクトリや拡張子も含めて指定する 例: "フォルダ名/hoge.csv")
* @return アップロードされたファイルのS3URI
*/
public static String fileUploadToS3(String strPresignedUrl, String filePath, String fileName) {
String command = "curl -X PUT --upload-file " + filePath + " " + strPresignedUrl + " -o /dev/null -w '%{http_code}\\n' -s";
try {
String bucketName = "xxxxxxxxx";
String key = fileName;
Process process = Runtime.getRuntime().exec(command);
InputStream input = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
StringBuffer out = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
// デフォルトだとシングルクォーテーションが入るっぽいので、削除する
out.append(line.replace("\'", ""));
}
String statusStr = out.toString();
reader.close();
input.close();
process.waitFor();
int status = Integer.parseInt(statusStr);
// レスポンスの結果が不正であれば例外を発生する
if(status != 200){
throw new Exception("S3へのファイルアップロードに失敗しました" + " ステータス:" + status + " ファイル名:" + fileName);
}
process.destroy();
// アップロード先のS3URIを返却
return "s3://" + bucketName + "/" + key;
} catch (Exception e) {
// 実運用で使用する場合は書き換え必須
e.printStackTrace() ;
}
}
※S3のバケット名(bucketName)は、コンソールを開いた際に直下に表示されているものになります。
ポイント
(1) Runtimeクラスのexecメソッドを使ってcURLコマンドを実行
本当は、HttpClientやHttpURLConnection辺りを使いたかったのですが、
①AWS SDK を使用して Amazon S3 の署名付き URL を作成する | aws
②Amazon S3署名済み URL での作業 | aws
③Java HttpURLConnectionを使ってファイルをアップロードする | Qiita
④luankevinferreira/UploadFile.java | GitHub Gist
あたりを参考に試行錯誤してもうまくいかなかったので、やむなくRuntimeクラスのexecメソッドでcURLを実行させることにしました。
(2) HTTPステータスコードでS3アップロードの正否を判断
Processクラスには、実行結果を判定するメソッドとして、
- waitFor()
- exitValue()
などがありますが、これらは実行した外部プロセスに関するもので、S3アップロードの正否は判断できません。
例えば、HTTPステータスコードが403で返ってきたとしても、waitFor()やexitValue()は、そのプロセス自体に問題がなければ正常終了を表す0になってしまいます。
そこで、無理やりな感じはしますが、cURL実行の戻り値をHTTPステータスコードのみにし、その値を取得して処理の正否を判断させることにしました。
以下、HTTPステータスコードだけを取得するcURLコマンドのサンプルです。
curl "http://hogehoge.example.com" -o /dev/null -w '%{http_code}\n' -s
(3) replaceメソッドで、HTTPステータスコード回りのシングルクォーテーションを削除
環境起因の可能性もありますが、HTTPステータスコードを取得したところ、「'200'」のようにシングルクォーテーションで囲われた値が変数に入っていたので、replaceにて置換させる処理を入れました。
終わりに
公式サイト等のサンプルコードを見てもなかなかうまくいかなかったので、cURLコマンドを使うという最終手段でなんとか。
もし、HttpClientやHttpURLConnectionで実現可能だよ、という方がいらっしゃったらぜひ教えてください~!
Discussion