はじめに
NTTデータ イントラマートにはIM-LogicDeignerという、intra-mart Accel Platform上でビジネスロジックをローコードで簡単に作成できるアプリケーションが提供されています。作成したロジックはREST APIとして利用可能です。
今回このIM-LogicDesignerを使って、AWSのS3 Presigned URLを用いたファイルアップロードする方法を紹介します。
S3 Presigned URL(署名付きURL)とは
S3 Presigned URL(署名付きURL)は、バケットポリシーを更新せずに一時的にS3内のオブジェクトへアクセスが可能となる署名付きのURLです。署名付きURLを使用することによって、AWS のセキュリティ認証情報やアクセス許可を持たずに、一時的にファイルのアップロードやダウンロードすることが可能となります。
今回は、IM-LogicDesignerからS3 Presigned URLを使って、S3へファイルアップロードしようとした際に問題となった点と、その解決方法について解説します。
背景
今回は、以下の流れでファイルをCSVファイルをアップロードしてみます。
実際のPresigned URLの生成はAWS LambdaからBoto3を使って、以下のような形で生成します。
import boto3
s3 = boto3.client("s3")
upload_url = s3.generate_presigned_url(
ClientMethod = "put_object",
Params = {
'Bucket': "bucket_name",
'Key': "object_key"
},
ExpiresIn = 500,
HttpMethod = "PUT"
)
通常はParamsパラメータにContent-TYpeを指定しますが、今回はこれが省略されていました。複数のContent-Typeを許容する目的でPresigned URL生成時にContent-Typeが指定されないということもあるかと思いますが、Presigned URLを使ってファイルアップロードする際には、Content-Typeが一致しないと受け付けません。つまり、この場合はファイルアップロード時にContent-Typeを省略する必要が出てきます。業務サーバ側の処理を変更すれば良いのですが、今回はIM-LogicDesignerからContent-Typeを省略したアクセスができる方法を試してみます。
問題点
まずはIM-LogicDesignerでHTTP通信を行う際の利用頻度の高い「ユーザ定義編集 - REST」の仕様を確認してみます。
リクエスト時にContent-Typeを指定する項目はなく、状況に合わせて自動付与される仕様です。
以下の条件を満たす場合にはContent-Typeの自動付与は行われませんが、今回はCSVファイルのアップロードをする目的ですので合致しません。
- リクエスト種別:raw
- 入力値の body パラメータの型:binary または byte[]
次に、HttpClientオブジェクトを用いた通信の仕様を確認します。
Content-Type省略時には以下の条件によってContent-Typeが指定される仕様です。
- 非マルチパート時:application/x-www-form-urlencoded
- マルチパート時:multipart/form-data
以上の点から、intra-martの標準機能ではIM-LogicDesignerから外部へのHTTP通信時にContent-Typeの指定を省略することはできない、ということになります。
対処方法
intra-martの標準機能では実現できないことがわかったので、IM-LogicDesigner の拡張機能を利用し独自のJavaタスクを生成する方法で対処します。
まずはJavaでContent-Typeを省略したHTTP通信の動作検証を行います。
public static void uploadFile(String targetUrl, File file) throws IOException {
// URLオブジェクトを作成
URL url = new URL(targetUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 接続設定
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
connection.setRequestProperty("Content-Length", String.valueOf(file.length()));
// ファイルをストリームとして送信
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
FileInputStream fileInputStream = new FileInputStream(file)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
}
// レスポンスコードを取得
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
// 接続を切断
connection.disconnect();
}
この方法で無事にファイルアップロードできました。ポイントは、curl -X PUT --upload-file file.csv URL
のようにcurlコマンドによるファイルアップロードと同等の処理とするために、ファイルをストリームとして送信する点です。
あとは、これをIM-LogicDesignerの拡張機能として取り込んで完了です。拡張モジュールの作成方法は、以下の手順で実行しintra-martのwarファイルに含めるように再ビルドを実行します。
おわりに
今回は、IM-LogicDesignerからS3 Presigned URLによるファイルアップロードする際に問題となった点の解消方法について説明を行いました。ただし、この問題はPresigned URL生成時にContent-Typeが指定されていないという点に起因した問題です。一般的にはPresigned URL生成時のロジックにて対処するのが通常だと思いますが、都合によってはその対処ができないケースに遭遇することもあるかもしれません。その際のご参考になれば幸いです。