Electronで画像をサーバに送信して保存する
今の組織で、フリーアドレスの推進のアシストアプリとして、かねてより作ってきた「座席表アプリ」について、新機能を都度都度追加しています。前回の「組織図」をElectronに移植し、今回は「顔写真を変更する」機能を搭載を考案。顔写真はサーバ側にあり、写真のファイル名は社員番号.jpgといった形で置いてある。
一般ユーザは自分のIDでログインし自分の写真のみ変更可とし、管理者は全員の写真に対して変更可にする必要性もある。ローカルの画像をElectronからサーバ側(Node.js)に送って、既存のファイルを置換しつつ、MySQLサーバのpictフラグを-1にするよう(写真未登録時のみ)にコードを追加する必要があるので、記録の為に下記に残します。
目次 [隠す]
今回使用するファイルやライブラリ
ExpressでAPIを作って画像ファイルの受け口を作るのは、前回の記事でも実装しています。続編的にはこちらの記事の続編です。
事前準備
サーバー側の準備
サーバー側の準備は至ってシンプルです。
- 画像保存用のフォルダを作成しておく(Node.jsから書き込めるパーミッションも設定しておく)
- npm init -yでプロジェクトを作成しておく
- 使用するモジュール(今回は、expressモジュールのみ)をインストールしておく
- index.jsを作成しコードを記述する
モジュールをインストールするコマンドは以下の通りです。
クライアント側の準備
keytarモジュールのインストールは非常に大変なので、こちらを参照してインストールしてください。それ以外で「今回必要な分のモジュール」をインストールしておきましょう。
保存先フォルダの準備
サーバー側の画像を保存するフォルダを用意します。今回は後に出てくるsavepath変数に格納するimgフォルダに保存することにします。問題はこの保存先が例えば、どこか別の場所(/var/www以下のサブディレクトリなど)に配置したい場合、そのまま指定すると、permission deniedとなり、保存が出来ません。
これは対象のフォルダについて、アクセス権限が無いが為に起きる現象で、以下の手順で対象のフォルダのアクセス権限を変更してみましょう。
- ターミナルからgroupコマンドで、自分自身の所属グループを調べる(今回はadmに所属していたのでこれを利用します)
- 次に、sudo nautilusにてファイラを起動、対象のフォルダまで移動し、右クリック⇒プロパティを開く
- 所有者は自分自身のアカウントにしておく。そして、グループはadmを指定。いずれも作成と削除を許可する
- 改めてアップロードを実施し、画像がアップできていればOK
図:結構な嵌りポイントです
ソースコード
クライアント側
クライアントであるelectron側では、ファイルの選択やBase64エンコード、MySQLのデータの読み書きなど様々な処理を担当しています。今回のコードは必要な箇所だけに絞っていますので、注意してください。
レンダラープロセス側
- メインプロセス側のファイル選択ダイアログの呼び出しと、アップロード結果を受け取るipcRendererだけが今回は行う仕事です。
メインプロセス側
- picturl変数にはサーバー側のPOSTで用意しておいたAPIのURLを入れる(ポート番号も含めて)
- showOpenDialogにて、画像のファイル形式のみを選択可能なようにfilter設定しています。
- filetypeモジュールにて、ファイルの拡張子およびMIMETYPEを取得しています。
- 変数base64manにbase64エンコードしたデータ含めて、変換と組み立てを行っています。
- chkpictFlg関数にて一度MySQLへログインさせて、pictフラグの取得をさせることで認証としています。
- requestモジュールでサーバー側のNode.jsで作成したAPIへPOST通信を送っています。この時、json:trueとしておくと、返り値をJSONパースした状態で取得可能です。
- リクエストを送って、サーバステータスコードの200が返ってきたら無事にリクエストは成功
- なおかつ、アップロード完了の返り値をサーバ側から受け取ったら、MySQLサーバの対象者のpictフラグを-1にしてあげるようにしています。
- chkpictFlgからのcallbackを拾って、無事に完了すればevent.sender.sendにてレンダラプロセスのIPCである「uploaded」へ最終的に返しています(ここで処理が完了。場合によっては、ここから更にレンダラプロセス側で画像のリロードなどを入れておくと良い)
サーバー側
サーバー側の主な処理は、
- APIで受け取ったBase64データをデコード
- 指定のフォルダに社員番号と拡張子を持ってして、ファイルを上書き生成
のみです。非常にシンプルな作業だけを担当させています。
- bodyParserのlimitを50MBに設定していますが、デフォルトは100KBです。画像ですので、適切なファイルサイズを指定しないと「request entity too large」のエラーが発生します。
- 今回は3700番ポートで/api/v1/pictchangeというURLにてPOST用のAPIを待機させてます。
- POSTで受信するので、app.postで受信したデータを冒頭で分解しています。
- savepathですが、このnode.jsのサーバがきちんと書き込めるパーミッションである必要があります。(今回は、このindex.jsがあるフォルダにimgフォルダを作っておきました)
- デコードはBuffer.fromで行います。new Bufferは現在非推奨ですので注意してください。
- fs.writeFileにてデコードしたデータをファイルに戻し、指定のフォルダに生成します。
- res.jsonにてクライアント側にレスポンスを返しています。
関連リンク
- Electron APIデモから学ぶ実装テクニック ― ネイティブUIと通信
- [Node.js]Basse64エンコード、Base64デコードしてみた
- Canvas(ブラウザ)からBase64変換した画像をNode.jsのサーバーに送って画像保存する #linebootawards
- Electron 画像をドラッグ&ドロップするだけでリサイズするアプリをつくる
- JavaScript(Node.js)を使った画像ファイルのBase64エンコード
- Express4でエラー「request entity too large」が発生する
- Node.js スクリプトからの HTTP 通信時にプロキシを通すには request が楽チン
- permission deniedで悩まされたので勉強してみた