GCSからファイルを取得してarchiveする
This commit is contained in:
parent
f1f4de1684
commit
7febf69c0c
3
.gitignore
vendored
3
.gitignore
vendored
@ -133,4 +133,5 @@ dist
|
|||||||
csv_output/
|
csv_output/
|
||||||
output/
|
output/
|
||||||
output.*
|
output.*
|
||||||
docments/
|
docments/
|
||||||
|
keys/
|
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}`);
|
||||||
|
};
|
||||||
|
```
|
15
package-lock.json
generated
15
package-lock.json
generated
@ -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",
|
||||||
|
@ -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"
|
||||||
|
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.
@ -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
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();
|
||||||
|
|
@ -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
|
||||||
|
};
|
||||||
|
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,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}/`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user