GCSからファイルを取得してarchiveする

This commit is contained in:
ry.yamafuji 2025-03-22 09:37:34 +09:00
parent f1f4de1684
commit 7febf69c0c
12 changed files with 262 additions and 14 deletions

3
.gitignore vendored
View File

@ -133,4 +133,5 @@ dist
csv_output/ csv_output/
output/ output/
output.* output.*
docments/ docments/
keys/

138
docs/cloudStorageByNode.md Normal file
View 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}`);
};
```

15
package-lock.json generated
View File

@ -11,7 +11,8 @@
"dependencies": { "dependencies": {
"@google-cloud/storage": "^7.15.2", "@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"
@ -601,6 +602,18 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/dunder-proto": { "node_modules/dunder-proto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",

View File

@ -2,11 +2,12 @@
"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": "",
@ -14,7 +15,8 @@
"dependencies": { "dependencies": {
"@google-cloud/storage": "^7.15.2", "@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"

View File

Binary file not shown.

View File

@ -14,6 +14,7 @@
<p >Server </p> <p >Server </p>
<button id="download-button-server">Zip Download(From Server)</button> <button id="download-button-server">Zip Download(From Server)</button>
<button id="download-button-upload">Zip Download(upload)</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> <script src="assets/downloadFromServer.js"></script>
</body> </body>

15
src/front/gcs.html Normal file
View 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
View 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();

View File

@ -8,7 +8,7 @@ const path = require('path');
* @param {http.ServerResponse} res * @param {http.ServerResponse} res
* @returns {void} * @returns {void}
*/ */
const downdloadContents = (req, res) => { const downloadContents = (req, res) => {
// ファイルの圧縮処理 // ファイルの圧縮処理
// CORSヘッダーを追加 // CORSヘッダーを追加
@ -87,5 +87,7 @@ const generateZipUrl = (req, res) => {
} }
module.exports = downdloadContents; module.exports = {
module.exports = generateZipUrl; downloadContents,
generateZipUrl
};

View 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;

View File

@ -1,8 +1,8 @@
const http = require('http'); const http = require('http');
// download/download.jsのdowndloadContentsメソッドをインポート
const downdloadContents = require('./download/download'); const { downloadContents, generateZipUrl } = require('./download/download');
// download/download.jsのgenerateZipUrlメソッドをインポート const downloadFilesFromGCS = require('./download/gcsArchive');
const generateZipUrl = require('./download/download');
/** /**
@ -17,11 +17,13 @@ const server = http.createServer((req, res) => {
res.end('Hello World\n'); res.end('Hello World\n');
} else if (req.url === '/downdload') { } else if (req.url === '/downdload') {
// ZIPファイルのコンテンツをそのまま返す // ZIPファイルのコンテンツをそのまま返す
downdloadContents(req, res); downloadContents(req, res);
} else if (req.url === '/generate-zip') { } else if (req.url === '/generate-zip') {
// ZIPファイルの生成してストレージのURLを返す // ZIPファイルの生成してストレージのURLを返す
generateZipUrl(req, res); generateZipUrl(req, res);
} else if (req.url === '/downdload-gcs') {
// GCSからZIPファイルのコンテンツをそのまま返す
downloadFilesFromGCS(req, res);
} else { } else {
res.statusCode = 404; res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain'); res.setHeader('Content-Type', 'text/plain');
@ -32,4 +34,6 @@ const server = http.createServer((req, res) => {
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}/`);
}); });