はじめに
Next.jsを使って、Google Cloud Storageに画像をアップロードしていきます。
今回コードを書くファイルは以下の2つです。
- 「src/pages/index.tsx」
- 「src/pages/api/upload.ts」
Next.jsにはAPIルートというものがあり、
pages/api内にあるファイルは '/api/*'にマッピングされ、APIエンドポイントとして使えます。
今回の場合は、'/api/upload'で扱う事ができます。
以下のような写真を入力し、アップロードするだけのシンプルなものを作っていきます。
githubにコードも置いています。少しだけ他のも混ざってます。すみません。
https://github.com/tokio-k/Gcs-Upload-Nextjs
GCP側の準備
GCPを開きます。
https://console.cloud.google.com/?hl=ja
検索の箇所に「認証情報」と入力し
1番上に来ている「認証と情報 APIとサービス」をクリックします。
認証情報のページに来たら、上部の「認証情報を作成」をクリックします。
認証情報を作成→サービスアカウントと進みます。
サービスアカウント名は任意の名前を入れてください。
ロールを選択で、Cloud Storageに権限を与えます。
完了をクリックし、サービスアカウントを作成します。
サービスアカウントが作成できたら、アカウントをクリックします。(メールアドレスの箇所)
サービスアカウントのページに来たら、「キー」のタブを選択し鍵を追加します。
新しい鍵を作成でjsonファイルを作成します。
このjsonファイルに様々な認証の情報が載っています。(他の人に見せてはいけません)
これで、GCP側の準備は完了です。
.env.localに追加していく
{} hello-world-project-311214...が先程作成したjsonファイルです。
(gitignoreでgitにあげないようにしてください。)
hello-world-project-311214-b2498….json
(追加するだけです。)
.env.localにjsonファイルのパスとプロジェクトIDを設定します。
PROJECT_ID=hello-world-proje....
GOOGLE_APPLICATION_CREDENTIALS="hell....85.json"
ライブラリのインストール
ターミナルで以下を実行して、ライブラリをインストールします。
yarn add @google-cloud/storage
コードの編集
index.tsx
(react-hook-formやuseStateなども使ってますがなくてもできます。)
import { useCallback, useState } from "react";
import { useForm } from "react-hook-form";
const IndexPage = () => {
const { handleSubmit } = useForm({defaultValues: {name:"", iconUrl:""}});
const [file, setFile] = useState<File>();
const handleChangeFile = (e: any) => {
setFile(e.target.files[0]);
};
const uploadImg = useCallback(async (file:File) => {
const fileName = "imgfile2"
const res = await fetch(`/api/upload?file=${fileName}`);
const { url, fields } = await res.json();
const body = new FormData();
Object.entries({ ...fields, file }).forEach(([key, value]) => {
body.append(key, value as string | Blob );
});
const upload = await fetch(url, {method:"POST", body});
if (upload.ok) {
console.log('Uploaded successfully!');
} else {
console.error('Upload failed.');
}
},[])
const handleClick = handleSubmit ( async () => {
if(file) {
uploadImg(file)
}
})
return (
<>
<div>
写真
<input
type="file"
accept="image/*"
onChange={handleChangeFile}
id="icon"
/>
<input type="submit" onClick={handleClick} />
</div>
</>
)
}
export default IndexPage;
inputの写真が変更された時に、handoleChangeFileが呼ばれて、
setFileでファイルをfileにセットしてる。
送信(input type submit)がクリックされた時に、setFileが呼ばれて、
fileを引数にuploadImgが呼ばれている
uploadImgが今回のアップロードの処理です。
uploadImgのみを抜粋
const uploadImg = useCallback(async (file:File) => {
const fileName = "imgfile2" ①
const res = await fetch(`/api/upload?file=${fileName}`);②
const { url, fields } = await res.json();
const body = new FormData();
Object.entries({ ...fields, file }).forEach(([key, value]) => {
body.append(key, value as string | Blob );
});
const upload = await fetch(url, {method:"POST", body});③
if (upload.ok) {
console.log('Uploaded successfully!');
} else {
console.error('Upload failed.');
}
},[])
①
fileNameはアップロードする画像の名前になります。
fileから名前を取得したり、ランダムな文字列を取得してつけると良いと思いますが、今回は固定にしています。
②
ここで、pages/api/upload.tsの処理が実行できます。
file=${fileName}はクエリパラメータです。情報を渡しています。
アップロードするためのurlや認証に関する情報などをレスポンスとして受け取っています。
③
実際に、画像をアップロードしている箇所です。
②で取得したurlや、その他bodyなどを使って画像をアップロードしています。
upload.ts
import { Storage } from "@google-cloud/storage";
export default async function handler(req: any, res: any) {
const storage = new Storage({
projectId: process.env.PROJECT_ID,
keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,
});
const bucketName = "sample-upload-img";
const bucket = storage.bucket(bucketName);
const file = bucket.file(req.query.file);
const options = {
expires: Date.now() + 1 * 60 * 1000,
fields: { "x-goog-meta-test": "data" },
};
const [response] = await file.generateSignedPostPolicyV4(options);
res.status(200).json(response);
}
req.query.fileにはクエリパラメータの値が入ってきます。
bucket.file("IconImage/" +req.query.file)などにすると、フォルダの中に画像を入れることも可能です。
bucketNameにはバケットの名前を入れます。
作成していなければ、Google Cloud Storageのサイト上部の「+バケットを作成」から、作成します。
これで、画像のアップロードの処理を書く事ができました。
最後に、CORSの設定をします。
CORSの設定
右上の赤丸の箇所をクリックして、画面下部の黒い画面を開きます。
ここからはこの画面で進めていきます。
プロジェクトに含まれるバケットを一覧表示します。
$ gsutil list
gs://sample-upload-img/
corsの設定を書くファイルを作成します。
$ touch cors_setting.json
corsの設定を記述していきます。
$ vim cors_setting.json
以下の様に書き換えます。
[
{
"origin": [
"http://localhost:3000"
],
"responseHeader": [
"Content-Type"
],
"method": [
"POST"
],
"maxAgeSeconds": 60
}
]
最後に、corsの設定ファイルの内容をバケットに設定します。
$ gsutil cors set cors_setting.json gs://sample-upload-img/
(確認もできます。)
gsutil cors get gs://sample-upload-img/
これで、corsの設定が完了しました。
これで画像がアップロードできる様になりました!
わからないところ、間違っているところがありましたらコメントお待ちしております。
参考文献
https://github.com/leerob/nextjs-gcp-storage
https://daiiz.hatenablog.com/entry/2017/03/05/001700