archive用の処理を追加する
This commit is contained in:
parent
ecf620d6ac
commit
37ba3e8532
@ -1,6 +1,17 @@
|
|||||||
|
|
||||||
# [Node.js]ファイルをZIP圧縮してダウンロードする方法
|
# [Node.js]ファイルをZIP圧縮してダウンロードする方法
|
||||||
|
|
||||||
|
- [\[Node.js\]ファイルをZIP圧縮してダウンロードする方法](#nodejsファイルをzip圧縮してダウンロードする方法)
|
||||||
|
- [圧縮処理について](#圧縮処理について)
|
||||||
|
- [方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)](#方法1フロンサイドで圧縮データを処理しファイルを保存するjszip)
|
||||||
|
- [方法2:サーバサイドで圧縮処理しファイルを出力する](#方法2サーバサイドで圧縮処理しファイルを出力する)
|
||||||
|
- [方法3:サーバサイドで圧縮処理しフロントでBlobによりファイルを取得する](#方法3サーバサイドで圧縮処理しフロントでblobによりファイルを取得する)
|
||||||
|
- [サンプルソース](#サンプルソース)
|
||||||
|
- [Blobを使用してZIPファイルを処理する(フロント側の処理)\*\*](#blobを使用してzipファイルを処理するフロント側の処理)
|
||||||
|
- [gcloudにあるファイルをzip形式でファイルを出力するサンプルソース](#gcloudにあるファイルをzip形式でファイルを出力するサンプルソース)
|
||||||
|
- [Zipダウンロードサーバを構築する(gcloud + express)](#zipダウンロードサーバを構築するgcloud--express)
|
||||||
|
|
||||||
|
|
||||||
## 圧縮処理について
|
## 圧縮処理について
|
||||||
|
|
||||||
* 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
|
* 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
|
||||||
@ -113,7 +124,7 @@ fetch("https://example.com/sample.zip")
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Gloudにあるファイルをzip形式でファイルを出力するサンプルソース
|
#### gcloudにあるファイルをzip形式でファイルを出力するサンプルソース
|
||||||
(スクリプト)
|
(スクリプト)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -154,3 +165,46 @@ async function downloadAndZip() {
|
|||||||
downloadAndZip().catch(console.error);
|
downloadAndZip().catch(console.error);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Zipダウンロードサーバを構築する(gcloud + express)
|
||||||
|
(サーバ)
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { Storage } = require('@google-cloud/storage');
|
||||||
|
const express = require('express');
|
||||||
|
const archiver = require('archiver');
|
||||||
|
|
||||||
|
const storage = new Storage();
|
||||||
|
const bucketName = 'your-bucket-name';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
app.get('/download-zip', async (req, res) => {
|
||||||
|
const filesToDownload = ['file1.csv', 'file2.csv']; // 圧縮したいファイルリスト
|
||||||
|
|
||||||
|
res.setHeader('Content-Type', 'application/zip');
|
||||||
|
res.setHeader('Content-Disposition', 'attachment; filename="compressed_files.zip"');
|
||||||
|
|
||||||
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||||
|
archive.pipe(res); // レスポンスに直接圧縮データを送る
|
||||||
|
|
||||||
|
for (const fileName of filesToDownload) {
|
||||||
|
const file = storage.bucket(bucketName).file(fileName);
|
||||||
|
const [exists] = await file.exists();
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
console.log(`Adding ${fileName} to archive...`);
|
||||||
|
archive.append(file.createReadStream(), { name: fileName });
|
||||||
|
} else {
|
||||||
|
console.warn(`File not found: ${fileName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
archive.finalize(); // ZIP 圧縮を完了
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server running at http://localhost:${port}`);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
72
src/front/assets/downloadFromServer.js
Normal file
72
src/front/assets/downloadFromServer.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// ダウンロードボタン
|
||||||
|
const downloadButtonServer = document.getElementById('download-button-server');
|
||||||
|
|
||||||
|
// ダウンロードボタンを押下した時の処理を記載する
|
||||||
|
downloadButtonServer.addEventListener('click', async () => {
|
||||||
|
// Blobで取得する方法
|
||||||
|
console.log('downloadButtonServer');
|
||||||
|
// ダウンロードボタンを無効化する
|
||||||
|
downloadButtonServer.disabled = true;
|
||||||
|
// ダウンロード処理を実行する
|
||||||
|
try {
|
||||||
|
// localhost:3000/downdload にリクエストを送る
|
||||||
|
const response = await fetch('http://localhost:3000/downdload');
|
||||||
|
if (!response.ok) throw new Error('Failed to fetch');
|
||||||
|
|
||||||
|
// ZIPファイルを取得
|
||||||
|
const zipBlob = await response.blob();
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = URL.createObjectURL(zipBlob);
|
||||||
|
a.download = "serverFile.zip";
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
} catch (e) {
|
||||||
|
// エラーが発生した場合
|
||||||
|
console.error(e);
|
||||||
|
alert('ダウンロードに失敗しました');
|
||||||
|
} finally {
|
||||||
|
// ダウンロードボタンを有効化する
|
||||||
|
downloadButtonServer.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ダウンロードボタン(アップロード)
|
||||||
|
const downloadButtonUpload = document.getElementById('download-button-upload');
|
||||||
|
|
||||||
|
// ダウンロードボタンを押下した時の処理を記載する
|
||||||
|
downloadButtonUpload.addEventListener('click', async () => {
|
||||||
|
console.log('downloadButtonUpload');
|
||||||
|
// ダウンロードボタンを無効化する
|
||||||
|
downloadButtonUpload.disabled = true;
|
||||||
|
// サーバーにアップロード処理APIを送信する
|
||||||
|
try {
|
||||||
|
// localhost:3000/generate-zip にリクエストを送る
|
||||||
|
const response = await fetch('http://localhost:3000/generate-zip');
|
||||||
|
if (!response.ok) throw new Error('Failed to fetch');
|
||||||
|
|
||||||
|
// レスポンスからURLを取得
|
||||||
|
const { url } = await response.json();
|
||||||
|
// 取得したURLを開く
|
||||||
|
window.open(url);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
// エラーが発生した場合
|
||||||
|
console.error(e);
|
||||||
|
alert('ダウンロードに失敗しました');
|
||||||
|
} finally {
|
||||||
|
// ダウンロードボタンを有効化する
|
||||||
|
downloadButtonUpload.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -11,6 +11,10 @@
|
|||||||
<p >Zip File Download</p>
|
<p >Zip File Download</p>
|
||||||
<button id="download-button">Zip Download(From Content)</button>
|
<button id="download-button">Zip Download(From Content)</button>
|
||||||
<button id="download-button-file">Zip Download(From File)</button>
|
<button id="download-button-file">Zip Download(From File)</button>
|
||||||
|
<p >Server </p>
|
||||||
|
<button id="download-button-server">Zip Download(From Server)</button>
|
||||||
|
<button id="download-button-upload">Zip Download(upload)</button>
|
||||||
<script src="assets/download.js"></script>
|
<script src="assets/download.js"></script>
|
||||||
|
<script src="assets/downloadFromServer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* ZIPファイルを作成してダウンロードサーバ
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* - ZIPファイルを作成してダウンロードするサーバー
|
|
||||||
* - Node.js + Express + archiver
|
|
||||||
*/
|
|
||||||
|
|
||||||
const express = require("express");
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const archiver = require("archiver");
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
const PORT = 3000;
|
|
||||||
|
|
||||||
app.get("/download-zip", async (req, res) => {
|
|
||||||
});
|
|
||||||
|
|
||||||
// ZIPのダウンロード用エンドポイント
|
|
||||||
app.use(express.static(__dirname));
|
|
||||||
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));
|
|
91
src/server/download/download.js
Normal file
91
src/server/download/download.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
const archiver = require('archiver');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* サーバサイドで圧縮処理しフロントエンドにファイルコンテンツを返す
|
||||||
|
* @param {http.IncomingMessage} req
|
||||||
|
* @param {http.ServerResponse} res
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
const downdloadContents = (req, res) => {
|
||||||
|
|
||||||
|
// ファイルの圧縮処理
|
||||||
|
// CORSヘッダーを追加
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*'); // すべてのオリジンを許可
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
// CSVファイル対象
|
||||||
|
const csvFilePaths = [
|
||||||
|
"./src/front/assets/data/test_data_1.csv",
|
||||||
|
"./src/front/assets/data/test_data_2.csv"
|
||||||
|
]
|
||||||
|
res.setHeader('Content-Type', 'application/zip');
|
||||||
|
res.setHeader('Content-Disposition', 'attachment; filename=test.zip');
|
||||||
|
|
||||||
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||||
|
|
||||||
|
archive.on('error', (err) => {
|
||||||
|
console.error('Archiver Error:', err);
|
||||||
|
res.statusCode = 500;
|
||||||
|
res.end('Internal Server Error');
|
||||||
|
});
|
||||||
|
|
||||||
|
// レスポンスに直接圧縮データを送る
|
||||||
|
archive.pipe(res);
|
||||||
|
|
||||||
|
// ZIPにファイルを追加
|
||||||
|
csvFilePaths.forEach((filePath) => {
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
archive.append(fs.createReadStream(filePath), { name: path.basename(filePath) });
|
||||||
|
} else {
|
||||||
|
console.warn(`File not found: ${filePath}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// ZIPファイルを作成
|
||||||
|
archive.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generateZipUrl
|
||||||
|
*
|
||||||
|
* @param {http.IncomingMessage} req
|
||||||
|
* @param {http.ServerResponse} res
|
||||||
|
*/
|
||||||
|
const generateZipUrl = (req, res) => {
|
||||||
|
// CORSヘッダーを追加
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*'); // すべてのオリジンを許可
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
// CSVファイル対象
|
||||||
|
const csvFilePaths = [
|
||||||
|
"./src/front/assets/data/test_data_1.csv",
|
||||||
|
"./src/front/assets/data/test_data_2.csv"
|
||||||
|
]
|
||||||
|
// ZIPファイルを生成してファイルを保存する
|
||||||
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||||
|
const zipFilePath = './src/front/assets/data/test.zip';
|
||||||
|
const output = fs.createWriteStream(zipFilePath);
|
||||||
|
archive.pipe(output);
|
||||||
|
|
||||||
|
// ZIPにファイルを追加
|
||||||
|
csvFilePaths.forEach((filePath) => {
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
archive.append(fs.createReadStream(filePath), { name: path.basename(filePath) });
|
||||||
|
} else {
|
||||||
|
console.warn(`File not found: ${filePath}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ZIPファイルを作成
|
||||||
|
archive.finalize();
|
||||||
|
|
||||||
|
// レスポンスにはURLを返す(~/assets/data/test.zip)
|
||||||
|
const url = `assets/data/test.zip`;
|
||||||
|
res.end(JSON.stringify({ url: url }));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = downdloadContents;
|
||||||
|
module.exports = generateZipUrl;
|
@ -1,9 +1,32 @@
|
|||||||
const http = require('http');
|
const http = require('http');
|
||||||
|
// download/download.jsのdowndloadContentsメソッドをインポート
|
||||||
|
const downdloadContents = require('./download/download');
|
||||||
|
// download/download.jsのgenerateZipUrlメソッドをインポート
|
||||||
|
const generateZipUrl = require('./download/download');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new HTTP server
|
||||||
|
*/
|
||||||
const server = http.createServer((req, res) => {
|
const server = http.createServer((req, res) => {
|
||||||
res.statusCode = 200;
|
// Set the response HTTP header with HTTP status and Content type
|
||||||
res.setHeader('Content-Type', 'text/plain');
|
// root path
|
||||||
res.end('Hello World\n');
|
if (req.url === '/') {
|
||||||
|
res.statusCode = 200;
|
||||||
|
res.setHeader('Content-Type', 'text/plain');
|
||||||
|
res.end('Hello World\n');
|
||||||
|
} else if (req.url === '/downdload') {
|
||||||
|
// ZIPファイルのコンテンツをそのまま返す
|
||||||
|
downdloadContents(req, res);
|
||||||
|
} else if (req.url === '/generate-zip') {
|
||||||
|
// ZIPファイルの生成してストレージのURLを返す
|
||||||
|
generateZipUrl(req, res);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res.statusCode = 404;
|
||||||
|
res.setHeader('Content-Type', 'text/plain');
|
||||||
|
res.end('Not Found\n');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user