LoginSignup
1
0

More than 5 years have passed since last update.

GAE上で大きなサイズのファイルを処理する

Last updated at Posted at 2017-07-17

環境

  • ruby歴 初心者
  • rails5
  • ruby 2.4.1p111

これはなに?

GAE に大きなサイズ(数百MB等)のファイルを処理する方法を記載したものです。

※細かい部分でもコメントをいただけると学びになりますのでよろしくお願いしますm(_ _)m

概要

まず、大きなファイルをどのようにアプリケーションに持っていくかで処理させる手法が変わってきます。
例えば、リクエストにファイルを乗せて、直接 GAE へのアップロードし処理する手法がまず思い浮かびますが
この手法ですと、制限が厳しく、特に下記の制限項目がまず壁となります。

・リクエストの処理が60秒を超えてはならない
・リクエストサイズが32MB以内

参考:
http://qiita.com/tomorier/items/7ee5222137651efddb33

そこで、今回、GAE に直接アップロードするのではなく
js から直接 GCS にアップロードし、アプリケーション側で、アップロードされたURLからデータをダウンロードして処理する手法を取りました。

実装

まず、前提として、アップロードするためアクセストークンが必要になります。
アクセストークンの取得についてはこちらをご参照ください。
処理としては、下記のフローで行います。

  1. ファイルを選択後、アップロードボタンを押下
  2. ajax にてアクセストークンを取得
  3. XMLHTTPヘッダーに必要な情報を付加
  4. アップロード

まずは、アップロードに必要なものを json で返すようにします。
ちなみに、GCS へのアップロードリクエストについてアップロード専用のリクエストである storage-upload.googleapis.com を使用すれば多少パフォーマンスが上がるようです。

uploader.rb
  def uploader_info

    key = "xxxx.zip"
    url = "https://storage-upload.googleapis.com/<バケット名>/#{key}"

    render json: { access_token: <アクセストークン>,
                   content_type: 'multipart/form-data',
                   upload_url: url,
                   redirect_url: <アップロード完了後のリクエスト先>,
                   redirect_params: {
                     storage_key: key
                   }
    }
  end

js側で、アップロードボタンを押下時に次の処理を走らせます。

uploader.js

$(document).on 'ready', ->
  $(document).on 'click', '#js-upload-submit-btn', ->
      $.getJSON(/uploader_info, (data) ->
        xhr = new XMLHttpRequest();
        xhr.open('PUT', data.upload_url);
        xhr.setRequestHeader('Authorization', 'Bearer ' + data.access_token);
        xhr.setRequestHeader('Content-Type', data.content_type);
        xhr.onload = uploadSuccess.bind(this, xhr, data)
        xhr.onerror = uploadFail.bind(this, xhr, data)

        input_file = $(document).find('input[type=file]');
        files = if input_file[0].files then input_file[0].files else [];
        xhr.send(files[0])
      )

  uploadSuccess = (xhr, data) ->
    if xhr.status == 200
      $.ajax
        type: "POST",
        url: data.redirect_url,
        dataType: "script",
        data: data.redirect_params,
    else
      //エラー

  uploadFail = (xhr, data) ->
    //エラー


これでアップロードできるはずですが、このままだとエラーが発生します。

CORS (Cross-Origin Resource Sharing)の適用

詳しい内容はこちらの参考ページをご参照ください。
(今回が初めての操作だったので、そもそもこのセキュリテイ自を知らなかったです。。。。。)

ざっくりの解釈だと、開いているWebページから別のWebページへのアクセスを禁止するセキュリティのようで、このセキュリティのおかげで悪質なサイトからのリクエストなどを防御しているということでしょうか。

そして、そのセキュリティをコントロールする仕組みが CORS (Cross-Origin Resource Sharing) と言うもののようです。

こちらの説明を見つつ、バケットにCORS設定を行っていきます。
コマンドラインからバケットに対して下記のjsonで設定を行いました。

cors.json
[
    {
      "origin": ["http://XXXXX.com"],
      "responseHeader": ["Authorization","Content-Type"],
      "method": ["PUT"],
      "maxAgeSeconds": 3600
    }
]

■origin

許可するホストを設定します。

■responseHeader

今回は下記の2項目を追加します。

  • Authorization
  • Content-Type

■method

今回は PUT のみにしました。

■maxAgeSeconds

レスポンスをブラウザでキャッシュする時間を秒単位で指定するとうなので、お好み。

結果

js から直接 GCS にアップロードすることができ、GAE の制限を回避してアプリケーションに大きなファイルを持ってくることができました!!!

学んだこと

・GAEの制限について
・ブラウザのセキュリティ(同一生成元ポリシー)
・CORS(Cross-Origin Resource Sharing)

参考

GAE/Goで大きなファイルを扱う
クロスオリジン リソース シェアリング(CORS)
Request URIs

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0