https://blogs.oracle.com/developers/controlling-your-cloud-uploading-large-files-to-oracle-object-storage
前回のエントリでは、OCI Java SDKでOracle Cloud Infrastructure(OCI)APIを操作する概要を説明しました。
Controlling Your Cloud - A Look At The Oracle Cloud Infrastructure Java SDKエントリ中で、SDKを掘り下げようとしたのは、OCI Object Storageへの大容量ファイルのアップロードを処理するためであると述べました。このエントリでは、実際にマルチパート・アップロードをやってみます。
http://blogs.oracle.com/developers/controlling-your-cloud-a-look-at-the-oracle-cloud-infrastructure-java-sdk
https://orablogs-jp.blogspot.com/2019/01/controlling-your-cloud-look-at-oracle.html
先に述べたように、HTTP(Hypertext Transfer Protocol)はもともと大きなファイル転送を扱うことを意図しておらず、ファイル転送は通常(そして多くの場合、依然として)FTP(File Transfer Protocol)を使って処理されていました。しかし、Web開発者はグローバルに分散されたクライアントを扱っており、FTPはサーバーのセットアップ、カスタムデスクトップクライアント、さまざまなファイアウォールルール、および認証を必要とするため、最終的に大きなファイルをHTTP/Sを使って転送してしまうのです。状況が許せば、Bit Torrentがより良い解決策になるかもしれませんが、Web開発者が扱っている分散ファイルはほとんどの場合解決策にはなりません。過去数年にわたるHTTPの多くの進歩のおかげで、大きなファイル転送が扱いやすくなりました。主な進歩は、(「チャンク」または「マルチパート」ファイルアップロードとして知られる)Chunked Transfer Encodingです。
Chunked Transfer Encodingマルチパートアップロードに関する Oracleのサポートについては、以下のドキュメントで詳細を説明していますが、できる限り簡単に説明するとすれば、ファイルをいくつかの部分(「チャンク」)に分割し、(必要に応じて同時に)アップロードし、すべての部分がアップロードされたら元のファイルに再構築するというものです。
https://en.wikipedia.org/wiki/Chunked_transfer_encoding
Using Multipart UploadsJava SDKを使ってマルチパートアップロードを実施するには、少なくとも3ステップ必要です。詳細を期したSDKのJavaDocsは以下からご覧いただけます。
https://docs.cloud.oracle.com/iaas/Content/Object/Tasks/usingmultipartuploads.htm
Oracle Cloud Infrastructure Java SDK - 1.3.3
https://docs.cloud.oracle.com/iaas/tools/java/latest/
- Initiate the multipart upload
- Upload the individual file parts
- Commit the upload
1. CreateMultipartUploadRequestDetailsインスタンスを含むCreateMultipartUploadRequestインスタンスを渡してObjectClient.createMultipartUploadを呼び出す。ステップ1を詳説すると、「ファイルをアップロードしたい。オブジェクト名はfoo.jpg、コンテンツタイプはimage / jpegだ。後でそのファイルの異なるピースを関連付けられるよう、識別子を教えてくれるかな?」とAPIに尋ねれば、APIはCreateMultipartUploadResponseの形で識別子を返してくれる、ということです。以下がそのコード例です。
ではアップロードを作成するために、objectNameとcontentTypeという引数を渡して、/oci/upload-createを呼び出します。Postmanを使って呼び出していますが、これはブラウザでfetch()を呼び出すのと同じくらい簡単です。
// route handler (Bootstrap.groovy):
post
"/oci/upload-create"
, { req, res ->
def
objectName = req.queryParams(
"objectName"
)
def
contentType = req.queryParams(
"contentType"
)
return
JsonOutput.toJson( objectService.createMultipartUpload(objectName, contentType) )
}
// service method (ObjectService.groovy):
def
createMultipartUpload(objectName, contentType=
"application/octet-stream"
) {
CreateMultipartUploadDetails createMultipartUploadDetails = CreateMultipartUploadDetails.builder()
.object(objectName)
.contentType(contentType)
.build()
CreateMultipartUploadRequest createMultipartUploadRequest = CreateMultipartUploadRequest.builder()
.namespaceName(namespaceName)
.bucketName(bucketName)
.createMultipartUploadDetails(createMultipartUploadDetails)
.build()
return
objectClient.createMultipartUpload(createMultipartUploadRequest)
}

これで今後の作業のためのアップロード識別子を取得しました(上図の2のuploadIdをご覧ください)。ではプロセスの2番目の手順に入ります。
2. uploadId、objectName、各パーツ用の連番(partNum)、チャンクされたファイルを含むUploadPartRequestのインスタンスを付けてObjectClient.uploadPart()を呼び出し、UploadPartResponseを受け取る。このレスポンスには、この後アップロードを完了するためにパーツの連番と共に保存しておくべきETagが含まれている。以下は手順2のコード例です。
これがPostmanのステップ2の呼び出しです。アップロードはファイルの各パートに対して1回実行されました。最後の手順で使用するため、ETag値を各パーツの連番(partNum)と共に保存します。
//route handler (Bootstrap.groovy):
post
"/oci/upload-part"
, { req, res ->
req.attribute(
"org.eclipse.jetty.multipartConfig"
,
new
MultipartConfigElement(
"/tmp"
))
HttpRequestWrapper reqRaw = req.raw()
InputStream is = reqRaw.getPart(
"uploadPart"
).getInputStream()
def
objectName = req.queryParams(
"objectName"
)
def
partNum = req.queryParams(
"partNum"
).toInteger()
def
uploadId = req.queryParams(
"uploadId"
)
return
JsonOutput.toJson( objectService.uploadPart(is, objectName, uploadId, partNum) )
}
//service method (ObjectService.groovy):
def
uploadPart(InputStream inputStream, String objectName, String uploadId,
int
partNum) {
UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
.namespaceName(namespaceName)
.bucketName(bucketName)
.objectName(objectName)
.uploadPartBody(inputStream)
.uploadId(uploadId)
.uploadPartNum(partNum)
.build()
return
objectClient.uploadPart(uploadPartRequest)
}

最後の手順3でアップロードが完了します。
3. objectName、uploadId、そしてCommitMultipartUploadPartDetailsの配列を含むCommitMultipartUploadDetailsインスタンスを含むCommitMultipartUploadRequestインスタンスを渡して、ObjectClient.commitMultipartUpload()を呼び出す。ややこしそうに見えますが、そnSounds a bit complicated, but it's really not. The code tells the story here:
呼び出すと、マルチパート・アップロードのコミットの完了を確認するシンプルなレスポンスが返ってきます。Object Storageのバケットに移動すると、アップロードされ再構築されたファイルの詳細を確認できます。
//route handler (Bootstrap.groovy):
post
"/oci/upload-commit"
, { req, res ->
/*
expects a JSON object in the request body that looks like this:
{
uploadId: "",
objectName: "",
uploads: [
{
partNum: 1,
ETag: "",
}
]
}
*/
Map body =
new
JsonSlurper().parseText(req.body())
def
details = []
body.uploads.
each
{ Map file ->
details << CommitMultipartUploadPartDetails.builder()
.partNum(file.partNum)
.etag(file.ETag)
.build()
}
return
JsonOutput.toJson( objectService.commitMultipartUpload(body.objectName, body.uploadId, details) )
}
//service method (ObjectService.groovy):
def
commitMultipartUpload(String objectName, String uploadId, List<commitmultipartuploadpartdetails> partDetails) {
CommitMultipartUploadDetails commitMultipartUploadDetails = CommitMultipartUploadDetails.builder().partsToCommit(partDetails).build()
CommitMultipartUploadRequest commitMultipartUploadRequest = CommitMultipartUploadRequest.builder()
.namespaceName(namespaceName)
.bucketName(bucketName)
.objectName(objectName)
.uploadId(uploadId)
.commitMultipartUploadDetails(commitMultipartUploadDetails)
.build()
return
objectClient.commitMultipartUpload(commitMultipartUploadRequest)
}
</commitmultipartuploadpartdetails>

そして、私たちがあらかじめ決められたURLで当該URL(もしくはバケットが公開されていれば直接)アクセスすれば、その画像を見ることができます。今回の場合は、ペットのMosesの写真です。
説明した通り、マルチパート・アップロード用のOracle SDKは、必要な手順に分類されていればかなり簡単に利用できます。適切なバックエンドサービスを利用できるのであれば、マルチパートアップロードを支援するためのフロントエンドライブラリが多数あります(今回は、MacBookのsplitコマンドを使って単純に分割しました)。
0 件のコメント:
コメントを投稿