0
0

Node.jsランタイムでSJISのcsvファイルを出力するLambda

Last updated at Posted at 2024-08-25

一覧データをcsv出力

データベースにはUTF-8で保管されているものの、
「ファイルの文字コードは Shift-JIS で(Excelでそのまま開きたいから)」
という要件があったとします。

今回は AWS Lambda(Node.jsランタイム) で構築したアプリケーションだったので、その例です。

ポイントは以下2点です。

  1. UTF-8からShift-JISへのエンコード
  2. Lambdaペイロード制限を考慮してS3署名付きURLを利用

まずはcsvデータを生成

csv形式へのパースにはPapa Parseを、エンコードにはencoding.jsを使うことにしました。
npm installしておきます。

DBから取得したデータ配列を渡して、csv形式&SJISエンコードした文字列を返す処理です。

const Papa = require('papaparse')
const encoding = require('encoding-japanese')

// CSV変換
const transformToCSV = (dataList) => {
  const config = {
    quotes: true, // 値をクォーテーションで囲む
    quoteChar: '"', // クォーテーション文字
    delimiter: ',', // 区切り文字
    newline: '\r\n', // 改行文字
    header: true // キーをヘッダーとして扱う
  }
  // CSV形式に変換
  const delimiterString = Papa.unparse(dataList, config)

  // 文字コード変換
  const strArray = encoding.stringToCode(delimiterString)
  const convertedArray = encoding.convert(strArray, 'SJIS', 'UNICODE')
  const uintArray = new Uint8Array(convertedArray)

  return uintArray
}

(参考ページ)

こちらの例のように、そのままレスポンスを返してフロントではBlobリンクを生成してダウンロードさせればよいのですが、ここで第2のチェックポイントです。

Lambdaでは6MBを超えるレスポンスは返せない

[ERROR] [************] LAMBDA_RUNTIME Failed to post handler success response. Http response code: 413.

このようなエラーが発生していたらこの制限にかかっているようです。

DBから取得した出力用データがこれを超えてしまう場合はどうするか?
S3 に転送して、署名付きURL を発行するのがよさそうです。
 以下の記事が参考になります。

先ほどのエンコード済みcsvデータをS3に転送して署名付きURLを取得する処理です。
AWS接続情報やバケット名などはconfigで別途管理しているものとします。

const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
const {
  GetObjectCommand,
  S3
} = require('@aws-sdk/client-s3');

// DL用URL取得
const getDownloadLink = async (csvData) => {
    // S3準備
    const s3 = new S3({
      credentials: {
        accessKeyId: config.aws.accessKeyId,
        secretAccessKey: config.aws.secretAccessKey
      },
      region: config.aws.region
    })

    // パス・ファイル名は任意
    const filename = 'sample_sjis.csv'
    const path = 'download/' + filename

    // S3にファイル転送
    const params = {
      Bucket: config.aws.bucket,
      Key: path,
      Body: csvData
     };
     await s3.putObject(params, function(err) {
      if (err) {
        throw new Error()
      }
     })

    // 署名付きURL取得
    const downloadUrl = await getSignedUrl(s3, new GetObjectCommand({
      Bucket: config.aws.bucket,
      Key: path,
      ResponseContentDisposition: 'attachment; filename="' + encodeURIComponent(filename) +'"'
    }), {
      expiresIn: 60 * 10
    })

  return downloadUrl
}

これをレスポンスとして返して、フロント側でURLにアクセスすればダウンロードが開始されます。

Lambda関数のメモリ設定 も必要に応じてご確認ください。

脚注

  • 24/8/27
    aws-sdk の箇所を v2 から v3 準拠に更新しました。

0
0
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
0
0