#はじめに
Webアプリを作る際にConohaのオブジェクトストレージに画像をアップロードするのが大変でしたので記事に書きました。
回覧板アプリ
サーバーサイドのNodeを経由した理由は、データベースでユーザー情報と画像ファイル名を紐付けして管理したいからです。
#画像アップロードの流れ
私が作成したWebアプリ内で画像アップロード方法は以下のようにしています。
1.ReactからNodeに画像を送信
2.NodeのMulterを使って、VPS内のフォルダに画像データを一時保存
3.オブジェクトストレージのトークン取得
4.NodeでVPSで一時保存している画像データをオブジェクトストレージへ送信
5.VPS内の一時保存している画像データを削除
#Conohaのオブジェクトストレージとは
Conohaが提供しているオブジェクトストレージで、特徴としては以下の通りです。
Conohaオブジェクトストレージ
1.データ転送料金無料
2.容量無制限
3.三重データコピーで耐障害性・信頼性
4.100GBあたり月額495円
5.RESTful API対応
#1.ReactからNodeに画像を送信
axiosを使ってNodeに画像を送信しています。
以下はフックの関数です。
const updateUserImage = useCallback((props: Props) => {
const { imageFile } = props;
const data = new FormData();
if (imageFile !== null){data.append('file', imageFile)};
const header = {
headers: {
"content-type": "multipart/form-data"
}
}
axios.post('APIのパス', data, header).then((res) => {
if(!res.data.success){
console.log('エラーです');
} else {
console.log('成功です');
}
}).catch((error) => {
console.log(error);
})
}, [])
#2.NodeのMulterを使って、VPS内のフォルダに画像データを一時保存
次にMulterを使って、Reactから送られてきた画像データをVPS内フォルダに保存します。
Multer
const multer = require('multer');
const uuid = require('uuid').v4;
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/temporary') //一時的に画像を保存するパスを指定
},
filename: (req, file, cb) => {
const { originalname } = file; //画像のオリジナルネームの取得
const fileName = encodeURI(`${uuid()}-${originalname}`); //uuidで差別化した名前に変更
cb(null, fileName);
}
})
const uploadAsync = (req, res) => {
return new Promise((resolve, reject) => {
upload(req,res,function(err){
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
reject(err);
} else if (err) {
// An unknown error occurred when uploading.
reject(err);
}
else {resolve()}
});
})
}
//画像アップロードのAPI
app.post('APIのパス',
(req, res, next) => {
uploadAsync(req, res).then(() => {
const file = req.file;
const imageName = file.filename;
//トークン取得など続きの動作がここから入る
})
}
)
#3.オブジェクトストレージのトークン取得
次にオブジェクトストレージのトークンを取得します。
const _ = require('lodash');
const httpRequest = require('request');
//以下にVPS内のAPI情報を入力します。
const tenantId = 'テナントID';
const username = 'ユーザー名';
const password = '設定したパスワード';
const api_url = 'https://identity.tyo2.conoha.io/v2.0';
const params = {
"url": api_url+'/tokens',
"headers": {
"Accept": 'application/json'
},
"form": JSON.stringify({
"auth": {
"passwordCredentials": {
"username": username,
"password": password
},
"tenantId": tenantId
}
})
};
app.post('APIのパス',
(req, res, next) => {
uploadAsync(req, res).then(() => {
const file = req.file;
const imageName = file.filename;
//トークン取得
httpRequest.post(params, function(err, result, body){
if (_.isString(body)) {
const res = JSON.parse(body);
const token = res.access.token.id;
const token_expire = res.access.token.expires;
console.log('token: ' + token);
console.log('expire: ' + token_expire);
//画像アップロード等の動作が続く
} else {
const res = body;
console.log(res);
}
})
})
}
)
#4.NodeでVPSで一時保存している画像データをオブジェクトストレージへ送信
最後に一時保存している画像データをオブジェクトストレージに送信します。
app.post('APIのパス',
(req, res, next) => {
uploadAsync(req, res).then(() => {
const file = req.file;
const imageName = file.filename;
//トークン取得
httpRequest.post(params, function(err, result, body){
if (_.isString(body)) {
const res = JSON.parse(body);
const token = res.access.token.id;
const token_expire = res.access.token.expires;
console.log('token: ' + token);
console.log('expire: ' + token_expire);
//画像アップロード
//ヘッダーの設定
const headers = {
'X-Auth-Token': token,
"Transfer-Encoding":"chunked"
};
// 送信先など
const options = {
//API情報に記載のあるオブジェクトストレージAPIエンドポイント
url: `https://object-storage.tyo2.conoha.io/v1/・・・/・・・/${imageName}`,
headers: headers,
}
fs.createReadStream(`public/temporary/${imageName}`)
.pipe(httpRequest.put( options , function(err , response , body){
console.log( response.headers );
console.log( 'ステータスコード:',response.statusCode);
console.log( body );
if(err)console.log(err);
else {
console.log( 'アップロードしました' );
}
}
} else {
const res = body;
console.log(res);
}
})
})
}
)
#5.VPS内の一時保存している画像データを削除
VPS内で一時保存している画像データは不要なので削除します。
fs.unlink(`public/temporary/${imageName}`, (err) => {
if (err) throw err;
})