🤖

拡張子ごとにContent-Typeを返すファイルダウンロードAPI

に公開

Excel/Wordのダウンロードで必要になるContent-Typeを、拡張子から判定してレスポンスで返すAPIが必要になったので作成してみました。

前提

フロントエンド側(Nextで作成)には拡張子付きでファイル名の一覧が表示されています。
ファイル名をクリックすると、そのファイルがダウンロードされるようなAPIを作成しました。
ファイルの拡張子は事前に決められています。

  • xlsx
  • xls
  • docx
  • doc

バックエンド側のファイルが保存されているフォルダは固定とします。

Excel(.xlsx.xls)やWord(.docx.doc)のファイルをサーバーからダウンロードするためには、Content-Typeをレスポンスで返す必要がありました。
Content-Typeとは、簡単に言うと「このファイルは○○という形式のファイルだよ」を示してくれるものです。

作成したAPI

[HttpGet("fileDownload")]
public async Task<IActionResult> FileDownload(string fileName)
{
    // ファイルのパス
    string _folder = @"D:\xx_sample\";
    string filePath = Path.Combine(_folder, fileName);

    if (!System.IO.File.Exists(filePath)) { 
        return NotFound("ファイルが見つかりません");
    }

    // MemoryStreamにファイルを読み込む
    MemoryStream memoryStream = new MemoryStream();
    using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        await fileStream.CopyToAsync(memoryStream);
    }

    // ポインタを先頭に戻す
    memoryStream.Position = 0;

    // コンテンツタイプを判定
    string contentType = GetContentType(filePath);

    return File(memoryStream, contentType, fileName);
}

// コンテンツタイプの判定
private string GetContentType(string filePath)
{
    var ext = Path.GetExtension(filePath).ToLowerInvariant();
    return ext switch
    {
        ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        ".xls" => "application/vnd.ms-excel",
        ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        ".doc" => "application/msword",
        _ => "application/octet-stream"
    };
}

GetContentType関数で拡張子によるContent-Typeを取得します。
今回の記事はここがメインなので、ここを少し解説します。
Path.GetExtensionメソッドでファイルの拡張子を取り出し、MIMEタイプを返却します。
(MIMEタイプとは、Web上データの形式を表すときにファイルのデータ形式を示すものです。)
フロントエンド側から送られてきたファイルの拡張子が.XLSXのように大文字の場合は、switchの分岐には当てはまらなくなってしまうため、ToLowerInvariantメソッドで小文字に変換しています。

冒頭にも書いた通り今回は拡張子がある程度決められているため、switchの分岐もそれに合わせています。
将来的にダウンロードするファイルが増えた場合はGetContentType関数にMIMEタイプを追加すればほかのファイルにも対応可能です。

さいごに

だいぶシンプルなAPIになりました。
もしうまくいかない場合はMIMEタイプの部分だと思います。
MIMEタイプも自動的に取得できれば一番良いですが、今回はファイルの種類が少ないのでこのままとしておきます。

Discussion