一覧データをcsv出力
データベースにはUTF-8で保管されているものの、
「ファイルの文字コードは Shift-JIS で(Excelでそのまま開きたいから)」
という要件があったとします。
今回は AWS Lambda(Node.jsランタイム) で構築したアプリケーションだったので、その例です。
ポイントは以下2点です。
- UTF-8からShift-JISへのエンコード
- 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 準拠に更新しました。