Compare commits
6 Commits
4ff8259c17
...
3a1b88493f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3a1b88493f | ||
![]() |
7febf69c0c | ||
![]() |
f1f4de1684 | ||
![]() |
b5a17b3e70 | ||
![]() |
37ba3e8532 | ||
![]() |
ecf620d6ac |
1
.gitignore
vendored
1
.gitignore
vendored
@ -134,3 +134,4 @@ csv_output/
|
|||||||
output/
|
output/
|
||||||
output.*
|
output.*
|
||||||
docments/
|
docments/
|
||||||
|
keys/
|
@ -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)](#zipダウンロードサーバを構築するgcloud)
|
||||||
|
|
||||||
|
|
||||||
## 圧縮処理について
|
## 圧縮処理について
|
||||||
|
|
||||||
* 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
|
* 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
|
||||||
@ -113,7 +124,7 @@ fetch("https://example.com/sample.zip")
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Gloudにあるファイルをzip形式でファイルを出力するサンプルソース
|
#### gcloudにあるファイルをzip形式でファイルを出力するサンプルソース
|
||||||
(スクリプト)
|
(スクリプト)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -154,3 +165,53 @@ async function downloadAndZip() {
|
|||||||
downloadAndZip().catch(console.error);
|
downloadAndZip().catch(console.error);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Zipダウンロードサーバを構築する(gcloud)
|
||||||
|
(サーバ)
|
||||||
|
|
||||||
|
```js
|
||||||
|
/**
|
||||||
|
* @fileoverview Google Cloud Storage (GCS) download module.
|
||||||
|
*/
|
||||||
|
const { Storage } = require('@google-cloud/storage');
|
||||||
|
const archiver = require('archiver');
|
||||||
|
const KEY_FILE_PATH = './keys/service-account.json'
|
||||||
|
const storage = new Storage({
|
||||||
|
keyFilename: KEY_FILE_PATH});
|
||||||
|
|
||||||
|
// Load environment variables
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
// バケット名を.envから取得する
|
||||||
|
const BUCKET_NAME = process.env.BUCKET_NAME;
|
||||||
|
console.log(`BUCKET_NAME: ${BUCKET_NAME}`);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GCStorageからファイルをダウンロードする
|
||||||
|
*
|
||||||
|
* @param {http.IncomingMessage} req
|
||||||
|
* @param {http.ServerResponse} res
|
||||||
|
*/
|
||||||
|
const downloadFilesFromGCS = async (req, res) => {
|
||||||
|
// バケットからファイル一覧を取得する
|
||||||
|
const [files] = await storage.bucket(BUCKET_NAME).getFiles();
|
||||||
|
const filesToZip = files.map((file) => file.name);
|
||||||
|
|
||||||
|
res.setHeader('Content-Disposition', 'attachment; filename="files.zip"');
|
||||||
|
res.setHeader('Content-Type', 'application/zip');
|
||||||
|
|
||||||
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||||
|
|
||||||
|
archive.on('error', (err) => res.status(500).send({ error: err.message }));
|
||||||
|
archive.pipe(res);
|
||||||
|
|
||||||
|
|
||||||
|
for (const fileName of filesToZip) {
|
||||||
|
const file = storage.bucket(BUCKET_NAME).file(fileName);
|
||||||
|
archive.append(file.createReadStream(), { name: fileName });
|
||||||
|
}
|
||||||
|
archive.finalize();
|
||||||
|
};
|
||||||
|
module.exports = downloadFilesFromGCS;
|
||||||
|
```
|
||||||
|
|
||||||
|
138
docs/cloudStorageByNode.md
Normal file
138
docs/cloudStorageByNode.md
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# [GCP][GCS]Node.jsライブラリでストレージを活用する
|
||||||
|
|
||||||
|
Node.jsのライブラリを使いストレージを制御します
|
||||||
|
|
||||||
|
## GCSとの連携について
|
||||||
|
|
||||||
|
セキュリティやアクセス制御の観点から、
|
||||||
|
フロントエンドは直接Cloud Storageにアクセスせず
|
||||||
|
サーバー経由で取得するのが一般的です
|
||||||
|
|
||||||
|
ただし静的なファイルや公開データであれば
|
||||||
|
フロントエンドから直接Cloud Storageにアクセスすることもあります
|
||||||
|
|
||||||
|
## ライブラリのインストール
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --save @google-cloud/storage
|
||||||
|
```
|
||||||
|
|
||||||
|
## GCS接続
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { Storage } = require('@google-cloud/storage');
|
||||||
|
```
|
||||||
|
|
||||||
|
**サービスアカウントを環境変数で設定する場合**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
const storage = new Storage()
|
||||||
|
```
|
||||||
|
|
||||||
|
**JSONキーファイルをソースで読み込む場合**
|
||||||
|
|
||||||
|
```js
|
||||||
|
const KEY_FILE_PATH = './keys/service-account.json'
|
||||||
|
|
||||||
|
const storage = new Storage({
|
||||||
|
keyFilename: KEY_FILE_PATH});
|
||||||
|
```
|
||||||
|
|
||||||
|
**JSONキーファイルを使わず直接設定**
|
||||||
|
|
||||||
|
```js
|
||||||
|
const serviceAccount = {
|
||||||
|
type: "service_account",
|
||||||
|
project_id: "your-project-id",
|
||||||
|
private_key_id: "your-private-key-id",
|
||||||
|
private_key: "-----BEGIN PRIVATE KEY-----\nYOUR-PRIVATE-KEY\n-----END PRIVATE KEY-----\n",
|
||||||
|
client_email: "your-service-account@your-project-id.iam.gserviceaccount.com",
|
||||||
|
client_id: "your-client-id",
|
||||||
|
auth_uri: "https://accounts.google.com/o/oauth2/auth",
|
||||||
|
token_uri: "https://oauth2.googleapis.com/token",
|
||||||
|
auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
|
||||||
|
client_x509_cert_url: "https://www.googleapis.com/robot/v1/metadata/x509/your-service-account"
|
||||||
|
};
|
||||||
|
const storage = new Storage({ credentials: serviceAccount });
|
||||||
|
```
|
||||||
|
|
||||||
|
## 権限について
|
||||||
|
|
||||||
|
* ストレージ管理者
|
||||||
|
*
|
||||||
|
* 環境とストレージ オブジェクト閲覧者
|
||||||
|
* Storage オブジェクト閲覧者
|
||||||
|
* ストレージ フォルダ管理者
|
||||||
|
|
||||||
|
## サンプルコード
|
||||||
|
|
||||||
|
### バケット一覧を取得する
|
||||||
|
|
||||||
|
```js
|
||||||
|
/**
|
||||||
|
* バケット一覧を取得する
|
||||||
|
*/
|
||||||
|
async function listBuckets() {
|
||||||
|
const [buckets] = await storage.getBuckets();
|
||||||
|
|
||||||
|
console.log('Buckets:');
|
||||||
|
buckets.forEach(bucket => {
|
||||||
|
console.log(bucket.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
ファイル検索については以下のページを参照してください
|
||||||
|
[[GCP]Google Cloud Storageでパターンにマッチしたファイル一覧を取得する](https://wiki.pglikers.com/en/private/cloud/gcp/gcs/glob)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### バケットの中のファイル一覧を取得する
|
||||||
|
|
||||||
|
```js
|
||||||
|
async function listFiles(bucketName) {
|
||||||
|
const [files] = await storage.bucket(bucketName).getFiles();
|
||||||
|
|
||||||
|
console.log(`Files in ${bucketName}:`);
|
||||||
|
files.forEach(file => {
|
||||||
|
console.log(file.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 署名付きURLを発行する
|
||||||
|
|
||||||
|
```js
|
||||||
|
/**
|
||||||
|
* 署名付きURLを生成する
|
||||||
|
*/
|
||||||
|
const generateV4ReadSignedUrl = async (bucketName, fileName) => {
|
||||||
|
const options = {
|
||||||
|
version: 'v4',
|
||||||
|
action: 'read',
|
||||||
|
expires: Date.now() + 15 * 60 * 1000, // 15 minutes
|
||||||
|
};
|
||||||
|
const [url] = await storage.bucket(bucketName).file(fileName).getSignedUrl(options);
|
||||||
|
console.log(`Generated GET signed URL:`);
|
||||||
|
console.log(url);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ファイルをダウンロードする
|
||||||
|
|
||||||
|
```js
|
||||||
|
// ファイルのコンテンツをダウンロードする
|
||||||
|
const downloadFile = async () => {
|
||||||
|
const options = {
|
||||||
|
destination: path.join(__dirname, FILE_NAME)
|
||||||
|
};
|
||||||
|
await storage.bucket(BUCKET_NAME).file(FILE_NAME).download(options);
|
||||||
|
// 取得したファイルのコンテンツからファイルを生成する
|
||||||
|
console.log(`Downloaded ${FILE_NAME}`);
|
||||||
|
};
|
||||||
|
```
|
@ -1,6 +1,9 @@
|
|||||||
## NodeでHttpサーバーを起動する方法
|
# [Node.js]NodeでHttpサーバーを起動及び構築する方法
|
||||||
|
|
||||||
### `http-server`を使う
|
## `http-server`を使う場合
|
||||||
|
|
||||||
|
http-serverはNode.js のシンプルな静的ファイルサーバーです。
|
||||||
|
インストールすれば簡単にローカルでファイルをホスティングできます。
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# http-server をグローバルインストール(初回のみ)
|
# http-server をグローバルインストール(初回のみ)
|
||||||
@ -13,3 +16,71 @@ cd src/front
|
|||||||
http-server
|
http-server
|
||||||
# http-server -p 3000
|
# http-server -p 3000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `http`モジュールを使う場合
|
||||||
|
|
||||||
|
* Node.jsの標準機能なので追加ライブラリなしで動作
|
||||||
|
* 軽量でシンプルな HTTPサーバーをすぐ作れる
|
||||||
|
* ルーティング機能がなく、URLごとに手動で条件分岐が必要
|
||||||
|
* ミドルウェア機能(ログ・認証・エラーハンドリング)がない
|
||||||
|
* 中~大規模開発には向かない(Expressのほうが便利)
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
const http = require('http'); // httpモジュールをインポート
|
||||||
|
|
||||||
|
// サーバーを作成
|
||||||
|
const httpserver = http.createServer((req, res) => {
|
||||||
|
res.writeHead(200, { 'Content-Type': 'text/plain' }); // HTTPステータス 200 とヘッダーを設定
|
||||||
|
res.end('Hello, Node.js Server!'); // クライアントへレスポンスを送信
|
||||||
|
});
|
||||||
|
|
||||||
|
// ポート3000でサーバーを起動
|
||||||
|
httpserver.listen(3000, () => {
|
||||||
|
console.log('Server running at http://localhost:3000');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## `Express`を使う場合
|
||||||
|
|
||||||
|
xpressはNode.jsの主要なWebフレームワークで
|
||||||
|
APIサーバーや動的ページの生成にも対応できます。
|
||||||
|
|
||||||
|
### インストール方法
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# プロジェクトフォルダを作成して移動
|
||||||
|
mkdir sample-express-app && cd sample-express-app
|
||||||
|
# npm 初期化
|
||||||
|
npm init -y
|
||||||
|
# Express インストール
|
||||||
|
npm install express
|
||||||
|
|
||||||
|
# `server.js` を作成して、以下を記述
|
||||||
|
node server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### サーバースクリプト
|
||||||
|
|
||||||
|
`server.js`を作成する
|
||||||
|
|
||||||
|
```js
|
||||||
|
// server.js
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
// 静的ファイルを提供
|
||||||
|
app.use(express.static('public'));
|
||||||
|
|
||||||
|
// ルートエンドポイント
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.send('Hello, Express!');
|
||||||
|
});
|
||||||
|
|
||||||
|
// サーバー起動
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server running at http://localhost:${port}`);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
0
keys/.gitkeep
Normal file
0
keys/.gitkeep
Normal file
878
package-lock.json
generated
878
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,18 +2,21 @@
|
|||||||
"name": "js-common-code",
|
"name": "js-common-code",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Javascriptで活用できるコードを開発する。 Node.jsによりサーバーサイドも作成する",
|
"description": "Javascriptで活用できるコードを開発する。 Node.jsによりサーバーサイドも作成する",
|
||||||
"main": "src/server/hellp.js",
|
"main": "src/server/index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
"doc": "docs"
|
"doc": "docs"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "node src/server/index.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@google-cloud/storage": "^7.15.2",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"csv-writer": "^1.6.0"
|
"csv-writer": "^1.6.0",
|
||||||
|
"dotenv": "^16.4.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"jsdoc": "^4.0.4"
|
"jsdoc": "^4.0.4"
|
||||||
|
0
src/front/assets/cloud-storage.js
Normal file
0
src/front/assets/cloud-storage.js
Normal file
BIN
src/front/assets/data/test.zip
Normal file
BIN
src/front/assets/data/test.zip
Normal file
Binary file not shown.
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,11 @@
|
|||||||
<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>
|
||||||
|
<p >Google Storage Link</p>
|
||||||
<script src="assets/download.js"></script>
|
<script src="assets/download.js"></script>
|
||||||
|
<script src="assets/downloadFromServer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
15
src/front/gcs.html
Normal file
15
src/front/gcs.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
||||||
|
<title>Google Cloud Storage</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>JavaScript Develop Download To Google Cloud Storage</h1>
|
||||||
|
<p >Zip File Download</p>
|
||||||
|
<button id="download-button">Zip Download(GCS)</button>
|
||||||
|
<script src="assets/cloud-storage.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
26
src/script/gcs.js
Normal file
26
src/script/gcs.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Google Cloud Storage (GCS) download module.
|
||||||
|
*/
|
||||||
|
const path = require('path');
|
||||||
|
const { Storage } = require('@google-cloud/storage');
|
||||||
|
|
||||||
|
const KEY_FILE_PATH = './keys/service-account.json'
|
||||||
|
// バケット名、ファイル名を.envから取得する
|
||||||
|
const BUCKET_NAME = process.env.BUCKET_NAME;
|
||||||
|
const FILE_NAME = process.env.FILE_NAME;
|
||||||
|
|
||||||
|
|
||||||
|
const storage = new Storage({
|
||||||
|
keyFilename: KEY_FILE_PATH});
|
||||||
|
|
||||||
|
// ファイルのコンテンツをダウンロードする
|
||||||
|
const downloadFile = async () => {
|
||||||
|
const options = {
|
||||||
|
destination: path.join(__dirname, FILE_NAME)
|
||||||
|
};
|
||||||
|
await storage.bucket(BUCKET_NAME).file(FILE_NAME).download(options);
|
||||||
|
// 取得したファイルのコンテンツからファイルを生成する
|
||||||
|
console.log(`Downloaded ${FILE_NAME}`);
|
||||||
|
};
|
||||||
|
downloadFile();
|
||||||
|
|
@ -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}`));
|
|
93
src/server/download/download.js
Normal file
93
src/server/download/download.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
const archiver = require('archiver');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* サーバサイドで圧縮処理しフロントエンドにファイルコンテンツを返す
|
||||||
|
* @param {http.IncomingMessage} req
|
||||||
|
* @param {http.ServerResponse} res
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
const downloadContents = (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 = {
|
||||||
|
downloadContents,
|
||||||
|
generateZipUrl
|
||||||
|
};
|
46
src/server/download/gcsArchive.js
Normal file
46
src/server/download/gcsArchive.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Google Cloud Storage (GCS) download module.
|
||||||
|
*/
|
||||||
|
const { Storage } = require('@google-cloud/storage');
|
||||||
|
const archiver = require('archiver');
|
||||||
|
const KEY_FILE_PATH = './keys/service-account.json'
|
||||||
|
const storage = new Storage({
|
||||||
|
keyFilename: KEY_FILE_PATH});
|
||||||
|
|
||||||
|
// Load environment variables
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
// バケット名を.envから取得する
|
||||||
|
const BUCKET_NAME = process.env.BUCKET_NAME;
|
||||||
|
console.log(`BUCKET_NAME: ${BUCKET_NAME}`);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GCStorageからファイルをダウンロードする
|
||||||
|
*
|
||||||
|
* @param {http.IncomingMessage} req
|
||||||
|
* @param {http.ServerResponse} res
|
||||||
|
*/
|
||||||
|
const downloadFilesFromGCS = async (req, res) => {
|
||||||
|
// バケットからファイル一覧を取得する
|
||||||
|
const [files] = await storage.bucket(BUCKET_NAME).getFiles();
|
||||||
|
const filesToZip = files.map((file) => file.name);
|
||||||
|
|
||||||
|
res.setHeader('Content-Disposition', 'attachment; filename="files.zip"');
|
||||||
|
res.setHeader('Content-Type', 'application/zip');
|
||||||
|
|
||||||
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||||
|
|
||||||
|
archive.on('error', (err) => res.status(500).send({ error: err.message }));
|
||||||
|
archive.pipe(res);
|
||||||
|
|
||||||
|
|
||||||
|
for (const fileName of filesToZip) {
|
||||||
|
const file = storage.bucket(BUCKET_NAME).file(fileName);
|
||||||
|
archive.append(file.createReadStream(), { name: fileName });
|
||||||
|
}
|
||||||
|
archive.finalize();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = downloadFilesFromGCS;
|
@ -1,12 +1,39 @@
|
|||||||
const http = require('http');
|
const http = require('http');
|
||||||
|
|
||||||
|
const { downloadContents, generateZipUrl } = require('./download/download');
|
||||||
|
const downloadFilesFromGCS = require('./download/gcsArchive');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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ファイルのコンテンツをそのまま返す
|
||||||
|
downloadContents(req, res);
|
||||||
|
} else if (req.url === '/generate-zip') {
|
||||||
|
// ZIPファイルの生成してストレージのURLを返す
|
||||||
|
generateZipUrl(req, res);
|
||||||
|
} else if (req.url === '/downdload-gcs') {
|
||||||
|
// GCSからZIPファイルのコンテンツをそのまま返す
|
||||||
|
downloadFilesFromGCS(req, res);
|
||||||
|
} else {
|
||||||
|
res.statusCode = 404;
|
||||||
|
res.setHeader('Content-Type', 'text/plain');
|
||||||
|
res.end('Not Found\n');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
console.log(`Server running at http://localhost:${port}/`);
|
console.log(`Server running at http://localhost:${port}/`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user