情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

expressモジュールによるHTTPサーバ(13)ファイルのダウンロード

この記事は「expressモジュールによるHTTPサーバ」という連載記事の13つ目の記事です。

その他の記事に関しては下を参照してください。

また、HTTP自体について知りたい方は下を参照してください。

この記事ではexpressモジュールを使ってHTTPリクエストに対してファイルをダウンロードさせるHTTPサーバを作成する方法について説明します。

ファイルのダウンロード

ブラウザが受け取ったHTTPレスポンスのボディのデータをローカルに保存させるにはHTTPレスポンスのContent-Dispositionヘッダフィールドをattachmentに設定する必要があります(また、必要に応じてfilenameパラメータを設定しなければなりません)。

Content-Dispositionフィールド

HTTPレスポンスのContent-Dispositionヘッダフィールドをattachmentに設定するにはres.attachment関数を使用します。

var express = require('express');

var app = express();
app.use(function (req, res, next) {
    res.attachment('xxx');
    next();
});

第1引数にContent-Dispositionヘッダフィールドのfilenameパラメータの値を指定します。この引数は指定しなくても構いません。

なお、HTTPレスポンスのContent-Typeヘッダフィールドには自動的に第1引数のファイル名の拡張子に対応するMIMEタイプが設定されます。

ファイルの送信

HTTPレスポンスのContent-Dispositionヘッダフィールドをattachmentに設定するだけでなく、HTTPレスポンスボディにファイルのデータを設定してレスポンスの送信までを行うにはres.download関数を使用します。

app.use(function (req, res, next) {
    res.download('xxx', 'yyy', function (err) {
        if (err) {
            res.sendStatus(err.status);
        }
    });
});

第1引数にファイルのパスを指定します。

第2引数にContent-Dispositionヘッダフィールドのfilenameパラメータの値を指定します。この引数は指定しなくても構いません。この引数を指定しなかった場合には第1引数のパスのファイル名がfilenameパラメータに設定されます。

第3引数にコールバック関数を指定します。この引数は指定しなくても構いません。

この関数の第1引数はエラーオブジェクトです。このエラーオブジェクトのstatusstatusCodeにはHTTPレスポンスに設定すべきステータスコードが格納されています

なお、HTTPレスポンスのContent-Typeヘッダフィールドには自動的に第1引数のパスの拡張子に対応するMIMEタイプが設定されます。

また、基本的にこの関数はHTTPレスポンスの送信も行いますが、第3引数のコールバック関数を指定した場合にエラーが発生した場合にはHTTPレスポンスの送信は行われませんので注意してください。

サンプルコード1

クライアントからGETリクエストを受け取ったら3番目のコマンドライン引数として与えられたファイルのデータをダウンロードするものとして返すHTTPサーバを作成し、起動します。

Enterキーが押されたらサーバを停止し、プログラムを終了します。

express-server-download.js

var express = require('express');
var http = require('http');

if (process.argv.length < 3) {
    console.error('lack argument.');
    process.exit(1);
}

var app = express();
app.set('env', 'development');
app.set('x-powered-by', false);
app.set('case sensitive routing', true);
app.set('strict routing', true);
app.get('*', function (req, res) {
    res.download(process.argv[2], function (err) {
        if (err) {
            console.error(err);
            res.status(err.status);
            res.send(http.STATUS_CODES[err.status] + '\r\n');
        }
    });
});
app.all('*', function (req, res) {
    res.status(501);
    res.send(http.STATUS_CODES[501] + '\r\n');
});
var server = app.listen(3000, function () {
    console.log('http server is running...press enter key to exit.');

    process.stdin.on('data', function (data) {
        if (data.indexOf('\n') !== -1) {
            server.close(function () {
                console.log('http server closed.');
                process.exit(0);
            });
        }
    });
});
server.on('error', function (err) {
    console.error(err);
    process.exit(1);
});

使用パッケージ

  • express
    npm install expressでインストールします。

実行結果

実行結果の確認のためにcURLを使用しています。

現在のフォルダにはtextfile.txtという名称のテキストファイルが存在しています(文字コードはUTF-8です)。

C:\work\node>type textfile.txt
これはテキストファイルの内容です。

3つ目のコマンドライン引数にこのテキストファイルを指定してコードを実行するとHTTPサーバが起動します。

C:\work\node>node express-server-download.js textfile.txt
http server is running...press enter key to exit.

cURLを使ってサーバに対してGETリクエストを行います。

C:\work\node>curl -v http://localhost:3000/
*   Trying ::1...
* Connected to localhost (::1) port 3000 (#0)
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.46.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Disposition: attachment; filename="textfile.txt"
< Accept-Ranges: bytes
< Cache-Control: public, max-age=0
< Last-Modified: Thu, 22 Sep 2016 06:47:40 GMT
< ETag: W/"38-15750a653f4"
< Content-Type: text/plain; charset=UTF-8
< Content-Length: 56
< Date: Thu, 29 Sep 2016 02:12:50 GMT
< Connection: keep-alive
<
���これはテキストファイルの内容です。
* Failed writing body (22 != 56)
* Closing connection 0
curl: (23) Failed writing body (22 != 56)

サーバから正しくレスポンスが返っていることが分かります。

また、ブラウザを使ってサーバに対してリクエストを行った場合にはブラウザでファイルのダウンロードが行われます。

Enterキーを押すとサーバが停止し、プログラムが終了します。

関連

pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-express, Node.js