LoginSignup
1
6

More than 5 years have passed since last update.

Webアプリでファイルのアップロードからダウンロードまでを一度の非同期通信で行う

Posted at

「クライアントからファイルを受け取り、サーバからもファイルを返す」という処理を1回のユーザ操作で実現したく調べた結果、fetch api、blobを使って実装したのでサンプルを記載しておきます。
サーバ側はDjangoです。

HTML側

sample.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <title>fetch sample</title>
    </head>
    <body>
        <form name="upload_form" onsubmit="myFetch()" method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            <input id="upload_file" type="file" name="file">
            <input type="submit" value="送信">
        </form>

        <script type="text/javascript">
            function myFetch(event) {
                // HTMLでの送信をキャンセル これをしないとページがリフレッシュされる
                event.preventDefault();

                let fd = new FormData( document.getElementById('upload_form') );

                fetch("/hogeURL", {
                    // ファイルを送信
                    method: "POST",
                    body: fd
                }).then(response => response.blob())
                .then(myBlob => {
                    // サーバからのレスポンスが完了
                    // サーバ処理でエラーが起きてもここに来る
                    console.log('完了');

                    // 内部的にBlobオブジェクトに対するリンクを生成&クリックしてダウンロード
                    let a = document.createElement("a");
                    a.style = "display: none";
                    a.href = URL.createObjectURL(myBlob);
                    a.download = 'ダウンロード用ファイル名';
                    document.body.appendChild(a);
                    a.click();
                }).catch(function(error) {
                    console.log('エラー:', error.message);

                });
            }
        </script>

    </body>
</html>

サーバ側

views.py
def upload(request):

    # サーバ内での処理の例 アップロードされたファイルを保存
    req_file = request.FILES['file']
    destination = open('ファイルを保存するパス', 'wb')
    for chunk in req_file.chunks():
        destination.write(chunk)

    # ファイルを返却
    response = HttpResponse(open('返却するファイルのパス', 'rb').read(), content_type='ファイルのMIME type')
    response['Content-Disposition'] = 'attachment; filename="返却時のファイルの名称"'

    return response

参考

Fetch API

1
6
0

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
6