- 投稿日:2019-11-28T22:45:45+09:00
Node.jsで、ファイルから1行ずつ読み込むためのreadlineモジュール
注意
この記事は初心者視点でザックリとした説明をしています。正確性に欠ける可能性がございますが、ご了承ください。「明らかに違うよ」ということがありましたら、ご指摘くださると幸いです。
Node.jsでファイルに1行ずつ書き込みたい。
Node.jsを使う際、.txtファイルや.csvファイルを一行ずつ読み込みたい場合がありました。
そんな時に使えるのがreadlineモジュールです。Node.jsで標準に備えられています。readlineモジュールの使い方
まずは以下のように、ファイルに書きます。
index.js'use strict'; //モジュールの読み込み const fs = require('fs'); const readline = require('readline'); //readstreamを作成 const rs = fs.createReadStream('./input.csv'); //writestreamを作成 const ws = fs.createWriteStream('./output.csv'); //インターフェースの設定 const rl = readline.createInterface({ //読み込みたいストリームの設定 input: rs, //書き出したいストリームの設定 output: ws }); //1行ずつ読み込む設定 rl.on('line', (lineString) => { //wsに一行ずつ書き込む ws.write(lineString + '\n'); }); rl.on('close', () => { console.log("END!"); });ストリームの作成
readlineを利用するときは、単独では使えずストリームと組み合わせて使わなければいけません。そのため、以下のように読み込みストリームと書き込みストリームを作成しています。
//readstreamを作成 const rs = fs.createReadStream('./input.csv'); //writestreamを作成 const ws = fs.createWriteStream('./output.csv');インターフェースの設定
以下の部分では、readlineでどのストリームを読み込むのか、どのストリームに書き出すのかの設定をしています。
//インターフェースの設定 const rl = readline.createInterface({ //読み込みたいストリームの設定 input: rs, //書き出したいストリームの設定 output: ws });1行ずつ読み込んでいく設定
最後に1行ずつ読み込んでいく設定です。
'line'イベントが起きたら(1行読み込まれたら)、その行がlineStringに代入されます、そしてws(書き込みストリーム)に書き込まれていきます。
そのままだと、ws(書き込みストリーム)に設定したファイルの最初の行に、読み込んだすべての行が書き込まれてしまうので、以下のように改行"\n"をつけています。//1行ずつ読み込む設定 rl.on('line', (lineString) => { //wsに一行ずつ書き込む ws.write(lineString + '\n'); });実行してみる
例えば、以下のファイルを1行ずつ読み込みたいとします。
input.csvほげ ほげほげ ほげほげほげ ほげほげほげほげ ほげほげほげほげほげ ほげほげほげほげほげほげ ほげほげほげほげほげほげほげ ほげほげほげほげほげほげほげほげ以下のようにJSファイルを実行します。
console$ node index.js > END!すると、書き込みたいファイルに以下のように、一字一句違わずに書き込まれているはずです。
output.csvほげ ほげほげ ほげほげほげ ほげほげほげほげ ほげほげほげほげほげ ほげほげほげほげほげほげ ほげほげほげほげほげほげほげ ほげほげほげほげほげほげほげほげ
- 投稿日:2019-11-28T21:52:06+09:00
toio と Unity の連携
はじめに
これは「toio™(ロボットトイ | toio(トイオ)) Advent Calendar 2019」の1日目の記事になります。
この記事ではUnityとtoioの連携方法を記します。
以下の記事・サイトを参考にしました。toio.js とは
toio.js は Node.js を用いたtoio公式のライブラリです。
パソコン側からcoreCubeを動かしたり、マット上の位置を取得したり出来ます。
今回はこれを使ってマット上のcoreCubeにUnity上のCubeを連動させたいと思います。環境
OS : MacOS High Sierra 10.13.6
下準備
Unity
Unity Hub のインストール
Unity Hub を入れます。
こちらのUnityHubをダウンロードからインストーラをダウンロードできます。unity hubを起動してインストールで最新バージョンのUnityを入れます。
このとき、Visual Studioも一緒にインストールします。
UniRx
プロジェクトが開いたらAssetストアで UniRx をダウンロード、インポートします。
すると、Assetsフォルダ下にPluginsフォルダができ、その中にUniRxが入ります。
C# websocketライブラリ
こちらからライブラリをダウンロードして解凍します。
中にある websocket-sharp.csproj をVisualStudioで開きビルドすると bin/Debug 下に websocket-sharp.dll が出来ます。
この websocket-sharp.dll を先ほど作成したプロジェクトの Assets/Plugins に入れます。
これでUnity側の下準備は完了です。
toio.js
brew install yarn
yarn に関しては公式では npm で入れていますが、
npm install -g yarn私は以下のように brew を使いました。
brew install yarn権限が必要だったり入れ難かった覚えがありましたが、なんかと入れたようです。
良くないことをしたかも知れません。toio.js
次に toio の github から toio.js を clone します。
公式曰く、以下のコマンドでパッケージのbuildまで済みます。
yarn example:hogehoge でサンプルプログラムが動きます。git clone https://github.com/toio/toio.js.git cd toio.js yarn install yarn build yarn example:keyboard-controlcoreCubeの電源を入れて接続され方向キーで動いたらオッケーです。
僕は接続されなかったのでパソコンを再起動したら動きました。実装
Unity側
SceneにCreateから3D Object/Cubeを置きます。
またCreateからUI/Buttonを置いておきます。Cube に Add Component/NewScript でPositionSyncというスクリプトをつけます。
以下、@nmxi さんの記事*から拝借したコードを改変して書いた中身です。PositionSync.csusing System.Collections; using System.Collections.Generic; using UnityEngine; using WebSocketSharp; using UniRx; public class PositionSync : MonoBehaviour { [SerializeField] private string _serverAddress; [SerializeField] private int _port; [SerializeField] private SyncPhase _nowPhase; private GameObject tA; private WebSocket ws; string message = ""; string messageA = ""; public float span = 0.5f; public enum SyncPhase { Idling, Syncing } private void Awake() { tA = GameObject.Find("Cube"); _nowPhase = SyncPhase.Idling; } void Update() { string[] m = message.Split(','); switch (m[0]) { case "A": if (message != messageA) { ////サイズの変更 //マット //559mm 410points //toioコアキューブ //31.8mm about 23.3point tA.transform.position = new Vector3(-(float.Parse(m[2]) - 250.0f) / 10.0f, tA.transform.position.y, -(float.Parse(m[1]) - 250.0f) / 10.0f); tA.transform.rotation = Quaternion.Euler(0, float.Parse(m[3]), 0); } messageA = message; //Debug.Log(m); break; } } /// <summary> /// Get Down Start Sync Button /// </summary> public void OnSyncStartButtonDown() { var ca = "ws://" + _serverAddress + ":" + _port.ToString(); Debug.Log("Connect to " + ca); ws = new WebSocket(ca); //Add Events //On catch message event ws.OnMessage += (object sender, MessageEventArgs e) => { message = e.Data; }; //On error event ws.OnError += (sender, e) => { Debug.Log("WebSocket Error Message: " + e.Message); _nowPhase = SyncPhase.Idling; }; //On WebSocket close event ws.OnClose += (sender, e) => { Debug.Log("Disconnected Server"); }; ws.Connect(); _nowPhase = SyncPhase.Syncing; } public void OnChangedTargetTransformValue(Vector3 pos) { if (_nowPhase == SyncPhase.Syncing) { //ws.Send(pos.ToString()); //ws.Send("1"); } } }Cube にある PositionSync (Script)の欄に
Server Address には "localhost"、Port には "8080"を入れて置きます。
先ほど置いたButtonのOn Click()に Cube/PositionSync/OnSyncStartButtonDown() を追加します。
toio.js側
toio.js/projectsフォルダを作成し、その中にスクリプトを置きます。
今回はtoio公式のサンプルと@nmxi さんの記事*から拝借したコードを悪魔合体して以下のスクリプトを生成しました。マット上におけるcoreCubeの絶対位置をUnityに送るプログラムです。
toio_node.jsconst { NearestScanner } = require('@toio/scanner') var WebSocketServer = require('ws').Server var wss = new WebSocketServer({ port: 8080 }); var cube; async function main() { // start a scanner to find nearest cube cube = await new NearestScanner().start() // connect to the cube await cube.connect() } main() wss.on('connection', function(ws) { //position-idに変化があった時 //移動、回転 //toioPositionを更新する cube.on('id:position-id', data => { ws.send("A,"+data.x+","+data.y+","+data.angle) }) //マットから離れた時 cube.on('id:position-id-missed', () => { // ws.send('Position Miss!'); }) });実行
1.coreCube の電源を入れます。
2.toio_node.js を実行します。(少しして coreCube から音がします。)
cd projects node toio_node.js3.Unity のプロジェクトを Run します。
4.GameView 上で Button をクリックします。
この状態でマットに置いた coreCube の位置が Unity の Cube に反映されれば成功です。
こんな感じ
[qiita用] マット上でのtoioCoreCubeの移動・回転がunityのSceneに反映されている pic.twitter.com/QJloUHmCeR
— ito.ur.right (@ito_ur_right) November 28, 2019
- 投稿日:2019-11-28T21:36:59+09:00
Node.jsでMySQLに接続するのをDockerでやってみた
この記事は富士通クラウドテクノロジーズ Advent Calendar 2019 5日目の記事です。
4日目は @tmtms さんの MySQL Parameters を拡張した でした。はじめに
- ※本記事は、 Node.js超入門[第2版] のサンプルコードをDocker上で動かす趣旨のものです。 よって、書籍で言及されている階層は触れません。
はじめまして。Node.jsを勉強中の新卒エンジニアです。
配属したてホヤホヤです。
今回は Node.js超入門[第2版] を使って勉強したときの話をします。この書籍の内容をDockerで実現しようとした経緯ですが、そのまま「Dockerを理解したかったから」です。
弊社の研修でもDockerについて触れていただいたのですが、一度教わっただけでは理解が難しいものでした。
というわけで、サンプルコードを写経するだけになりがちだった(主観です)プログラミングの本で、ついでに理解を深めようという魂胆です。今回は、書籍の Chapter5「値とデータをマスターしよう!」の、Section5-3~5-4 で書かれている、Node.jsでDBにアクセスして情報を取得し、ブラウザに表示するプログラムを紹介します。書籍が手元にある方はぜひ確認してみてください。
環境構築
必要な環境
- Linux
- Docker https://docs.docker.com/install/
- docker-compose https://docs.docker.com/compose/install/
- 今回のコードは GitHub にpushしました。以降、これを読んでいるものとして話を進めます。
参考記事:
解説
- 今回は、Node.jsもMySQLも、Dockerコンテナとして生成しています。
- Node.jsサーバーは、
docker-compose.yml
からDockerfile
を呼び出す形で書き、MySQLサーバーはdocker-compose.yml
内で定義しています。docker-compose.yml
で指定するMySQLのDockerイメージは、MySQLのバージョンが8よりも前になるように古いものを使っています。 8以降はそのままだとNode.jsとの連携ができないようです。init-mysql.sh
は、ローカル環境から、データベース用のコンテナにアクセスし、テーブル作成->データ挿入までを行っています。- 実は、
docker/db/my.cnf
とdocker-compose.yml
の2か所でmysqld
を設定しているのですが、どちらかを消すとなぜかエラーになってしまうため(!)そのままにしてあります。いい方法ががありましたら教えていただけると幸いです・・・。- 余談ですが、今回のコードは、いままで述べてきたものとは別のDockerfileでExpress-generatorを実行し、
docker cp
でローカルにファイルをコピーしてから作成していきました。 めんどうくさいことをしたなと自分で思います。動作確認
- 上記のリポジトリをcloneします。
- リポジトリに移動
docker-compose up -d
でコンテナを立ち上げます。- すこし(10秒ほど)時間をおきます。(コンテナが出来上がるまで待つ)
- ローカルで
./init-mysql.sh
を実行します。localhost/hello
にアクセスし、docker/db/sql/002-insert-records.sql
で入れたデータが表示されていることを確認してください。- ↓ こんなふうに表示されます。
おわりに
まず、Node.jsについての書籍を読み、サンプルを実行してみることで、Node.jsの挙動についてざっくりと理解できるようになりました。
加えて、それらをDocker上の環境で行うことで、
いままで「VirtualBoxより軽い仮想化するアプリケーション?」という認識だったDockerについての理解も深まりました。
Linuxのコンソールの扱いも以前よりわかるようになってきました。
やっと.profile
や.vimrc
をカスタマイズできるようになり、快適なUbuntu生活をしております。また、試行錯誤して、調べたり人に聞いたりしていくことが学びへの近道だと実感しました。
例えば、MySQLのバージョンに関しては自分では調べきれず、先輩方の知恵をお借りしました。
ありがとうございました。まだまだエンジニアとしては若輩者ですが、これからもっと勉強してスキルをつけ、開発をたくさんしていけたらと思います。
- 投稿日:2019-11-28T19:10:30+09:00
DOMについて調べたことの備忘録
DOMについて
- Document Object Model
- HTML や XML 文書を操作するための、たくさんの機能や規則のこと
- DOMは階層構造をとる
- 各要素はノードという単語を用いて表現される
ノードについて
- ノード
- 子ノード(children)
- 親ノード(parent)
- 兄弟姉妹ノード
- ノードは、webページとプログラミング言語をつなぐ役割を持つ
- ID名からノードを取得、操作する
DOMとは何か?【JavaScript初心者向けにわかりやすく説明します!】
DOMの話に戻ります
HTML要素の取得:getElementById()
- Documentオブジェクトのメソッドである「getElementById()」が一般的らしい
- 文字列のHTMLタグを認識できる
使用例
<body> <p id="text">これはサンプルテキストです</p> <script> var p = document.getElementById('text'); console.log( p ); </script> </body>実行結果
<p id="text">これはサンプルテキストです</p>HTML要素をJavaScriptから書き換える:innerHTMLプロパティ
- 「innerHTML」プロパティを代入するだけ!
使用例
<div id="wrap"> <p>これはサンプルテキストです</p> </div>これをinnerHTMLプロパティでp要素をh1要素に書き換える
var div = document.getElementById('wrap'); div.innerHTML = "<h1>サンプルタイトル</h1>"; console.log( div );実行結果
<div id="wrap"> <h1>サンプルタイトル</h1> </div>JavaScriptからHTML要素を作成する:createElement( )
- もっとも簡単な方法はcreateElement()
- 例えば「createElement('p')」と記述することで「p要素」を新規に生成
var pElement = document.createElement('p');
- この方法で作成しても、画面に表示されないので、HTML要素をDOMに追加しなくてはならない
HTML要素を追加:appnedChild()
- JavaScript側で生成したHTML要素をDOMに追加
var p = document.createElement('p'); //テキストを追加する p.textContent = 'これはサンプルです'; //body要素内にp要素を配置する document.body.appendChild( p );実行結果
<p>これはサンプルです</p>※ textContent()メソッドでテキストを追加
DOMが読み込まれるタイミング:onloadイベント
- DOMによるオブジェクト化がされていないと、JavaScript側からHTMLを操作できない
- DOMが読み込まれた後にJavaScriptが実行できるようにしなければならない
- その中で、もっとも簡単なのがonloadイベント
dow.onload = function() { //ここに処理を書く }
- しかし複数記述すると、その都度上書きされてしまうので、上に書いたものは実行されない・・・
window.onload = function() { //処理1 } window.onload = function() { //処理2 } window.onload = function() { //処理3 }
- こちらの処理は一番下しか実行されない
onloadでなくaddEventListenerを使ってみる
使用例
window.addEventListener('load', function() { //処理1 }) window.addEventListener('load', function() { //処理2 }) window.addEventListener('load', function() { //処理3 })
- 第一引数にloanを書き、第二引数に実行する関数処理をかく
- addEventListenerを使用することで、3回記述したとしても全て実行することができる
- 投稿日:2019-11-28T17:26:31+09:00
LINE Notifyのnpmライブラリ作ったのでサンプルソースを紹介する
はじめに
LINE Notify APIのNode.jsライブラリを作りました。
https://www.npmjs.com/package/line-notify-nodejs使い方とサンプルソースを紹介します。
使用イメージ
インストール
$ npm install line-notify-nodejs使い方
簡単2STEPです。
STEP1. トークンを発行する
下記ページからトークンを発行します。
STEP2. 通知を送信する
index.jsconst lineNotify = require('line-notify-nodejs')('kQnesu**********************'); // 先ほどコピーしたトークン lineNotify.notify({ message: 'send test', }).then(() => { console.log('send completed!'); });$ npm run index.js
- 投稿日:2019-11-28T17:26:31+09:00
LINE Notifyのnpmライブラリ作ったので紹介する
はじめに
LINE Notify APIのNode.jsライブラリを作りました。
https://www.npmjs.com/package/line-notify-nodejs使い方とサンプルソースを紹介します。
使用イメージ
インストール
$ npm install line-notify-nodejs使い方
簡単2STEPです。
STEP1. トークンを発行する
下記ページからトークンを発行します。
STEP2. 通知を送信する
index.jsconst lineNotify = require('line-notify-nodejs')('kQnesu**********************'); // 先ほどコピーしたトークン lineNotify.notify({ message: 'send test', }).then(() => { console.log('send completed!'); });$ npm run index.js
- 投稿日:2019-11-28T17:26:31+09:00
LINE Notifyのnpmライブラリ作った
はじめに
LINE Notify APIのNode.jsライブラリを作りました。
https://www.npmjs.com/package/line-notify-nodejs使い方とサンプルソースを紹介します。
使用イメージ
インストール
$ npm install line-notify-nodejs使い方
簡単2STEPです。
STEP1. トークンを発行する
下記ページからトークンを発行します。
STEP2. 通知を送信する
index.jsconst lineNotify = require('line-notify-nodejs')('kQnesu**********************'); // 先ほどコピーしたトークン lineNotify.notify({ message: 'send test', }).then(() => { console.log('send completed!'); });$ npm run index.js
- 投稿日:2019-11-28T15:58:16+09:00
[kintone] node.jsで開発環境のフィールド権限を本番環境に反映する
概要
開発環境を本番環境に反映する際、フィールド権限などはアプリテンプレートでは
持ってこれないのでcli叩いてやりたかった。
kintone-cliとか便利なツールあるのでそれ使えたら使ったほうがいいと思います。
今回しか使わない捨てコードなので適当ですがmain.jsconst request = require("request"); const params = { url: "開発用のドメイン/k/v1/field/acl.json?app=1", method: "GET", json: true, headers: { "X-Cybozu-Authorization": "ログイン名とPWをBase64エンコードしたもの" }, }; request(params, (err, res, body) => { if (err) { console.log('err :', err); return; } const Admine = "本番用ドメインのログイン名とPWをBase64エンコードしたもの"; params.url = "本番用ドメイン/k/v1/field/acl.json" params.headers["X-Cybozu-Authorization"] = Admine; params.method = "PUT"; params.json = { "app": 1, "rights": body.rights }; request(params, (err, res, body) => { if (err) { console.log('err :', err); return; } console.log('body :', body); }); });$ node main.js
したあとRevisionのログ流れたらOK
- 投稿日:2019-11-28T14:28:24+09:00
ローカル環境で LINEWORKS Bot を動かす話
LINEWORKS Advent Calendar 2019 の 3日目を担当させていただきます!
どうぞよろしくおねがいしますm( )mさっそくですが、タイトルの通りローカル環境で LINEWORKS Bot を動かす話をしたいと思います。
開発用に自由に使えるサーバを持ってない私にとって、LINEWORKS Bot を実際に動かすのに GoogleAppsScripts が便利なのでよく使っています。
ですが、Node.js が基本スキルの私にとって、GAS は Javascript に近い作りですが微妙に違ってくるので、やっぱりちゃんと Node.js のコードでテストしたい!って思うわけなのです。ローカル環境でトーク Bot を動かすには、
1. ローカル環境に http サーバを立ててアプリケーションを動かして
2. 外部公開用の URL を取得して Bot の Callback URL に登録すると、いう流れになりますねー。
では、さっそくやっていきますね。ローカル環境に http サーバを立ててアプリケーションを動かす
たぶん、読んでる方々には釈迦に説法状態だと思うので、非常に恐縮なのですが。。。
Node.js にはexpress
という、すんばらごいモジュールがいらっしゃいます。(゚Д゚)ノ
知っている方は読み飛ばしていただいて結構ですよ!( ;∀;)では、
express
をさくっとインストールしていきましょー。と、その前に
package.json
ファイルを作ります。
このアプリケーションはこんなアプリケーションですよーってファイルです。
「わかってるよ!もうあるよ!」って方はごめんなさい。読み飛ばしてください。以下のコマンドを実行してください。
> npm init英語で質問されるので、ペラペラバイリンガルなあなたは適切に答えていただければ大丈夫!
英語得意じゃないので全部Enter
!(゚Д゚) それでも大丈夫!
package.json
ファイルが作成されますので、中身を開いてみてください。真ん中らへんに
"start"
の項目があると思うので以下のように書き換えます。"scripts": { "start": "node ./app.js" },設定が終わったら
express
をインストールします。> npm install express --saveインストールが終わったら、アプリケーションのコードを書いていきましょう!
単純に、メッセージを受け取ってコンソールに表示するだけのプログラムです。app.jsconst express = require('express'); const app = express(); const port = xxxx; // port には任意の値を入れてください。 app.listen(port); app.post('/callback', function(req, res) { console.log(req.body); });
npm start
で実行してアプリケーションを起動させます!> npm startこれで準備は OK です!
次の手順に進みましょう。外部公開用の URL を取得して Bot の Callback URL に登録する
ローカル環境を外部公開するなんて、どうしたらいいのやらやら。
そんなとき大活躍してくれる強い味方! ngrok さんです!ヾ(´∀`)ノ・・・なんか、モジュール紹介になってる気もしますが、これ、全部 LINEWORKS Bot を使うためですから!(^_-)-☆
ngrok
さんを使えば、ローカル環境のサーバを外部公開できます!
LINEWROKS Bot の Callback URL はhttps
でないといけないのですが、もちろんngrok
さんはhttps
の URL を作成してくれんですよ~。ありがたい(*´Д`)それでは、さくさくっといきましょー。
まずは、別のターミナルを起動してngrok
さんをインストールしてください。> npm install ngrok --saveそして、あとはコードを書いて実行するだけ。
getCallbackUrl.jsconst ngrok = require('ngrok'); const port = xxxx; // port には任意の値を入れてください。 ngrok.connect(port).then((ngrokUrl) => { console.log('bot callback URL : ' + ngrokUrl + "/callback"); });すると、ローカル環境がサーバとなり、URL が発行されます。
> node .\getCallbackUrl.js bot callback URL : https://ff7b9d27.ngrok.io/callbackあとはこの URL を Bot に登録すれば OK!
こんなに楽チンにhttps
の URL が取得できちゃうなんて、ありがたいですよねー(*´Д`)API で Callback URL を登録する
ngrok での URL はプログラムを終了すると取得しなおしになるので、その度に Bot に登録し直しになります。
次の日とか、URL 取り直してー、登録し直してー、ってやらないといけません。
めんどいっ!(゚Д゚)ノURL を取得したらそのまま登録しちゃえばいいんですよ!
ってなわけで、さっきのコードを改造していきます。Callback URL を登録するのに API を使うので
request-promise
モジュールを先にインストールしておきます。> npm install request-promise --save普通の
request
モジュールでもいいのですが、request-promise
だとエラー処理が.catch
でできるので愛用しています。
インストールしたら準備は OK!
コードを書いていきましょう。setCallbackUrl.jsconst ngrok = require('ngrok'); const port = xxxx; // port には任意の値を入れてください。 const request = require('request-promise'); ngrok.connect(port).then((ngrokUrl) => { console.log('bot callback URL : ' + ngrokUrl + "/callback"); const options = { // apiId,consumerKey,token,botNo はご自身のものを入力してください。 uri: "https://apis.worksmobile.com/" + apiId + "/message/setCallback/v2", headers: { "Content-type": "application/json", "consumerKey": consumerKey, "Authorization": "Bearer " + token }, json: { "botNo": botNo, "callbackUrl": ngrokUrl + "/callback", "callbackEventList": ["text", "sticker"] } }; request.post(options).then((body) => { console.log(body) }) .catch((error) => { throw new Error(error) }); });では、実行して Callback URL を登録しましょう!(=゚ω゚)ノ
> node setCallbackUrl.js bot callback URL : https://252b7e9b.ngrok.io/callback { message: 'OK', code: 200 }200 OK をもらいましたが、念のため DeveloperConsole でも確認しましょう。
ちゃんと、登録されていますね!
これで、完成です!さぁ、Bot に話しかけてみよう
初めての方に話しかけるのは緊張しますよね!
ここはビシッと!格好よく!トークしましょう!
{ type: 'message', source: { accountId: 'xxxxx@yyy-zzz', roomId: '26280667' }, createdTime: 1574917451022, content: { type: 'text', text: 'hogehoge' } }送ったメッセージが
app.js
のコンソール画面に表示されましたね。
成功です!(*'▽')やったーおわりに
ここまでお付き合いいただきありがとうございました。
改めて、LINEWORKS Advent Calendar 2019 の3日目として参加させていただきありがとうございました。
少しはかしこまって書こうかな?とか考えていたのですが、結局いつも通りのテンションでした(=゚ω゚)
本当に申し訳なく思っておりますまる。5日目にもエントリーしてるので、またどうぞよろしくお願いします~('ω')
ではまた!(^^)/
参考にさせていただきましたm(_ _)m
- 投稿日:2019-11-28T13:21:04+09:00
Node.js + axios で 画像をFormDataでアップロードしようとしてハマった話
やりたかったこと
Node.jsのスクリプトでローカル上の画像ファイルを
mulitpart/form-data
で送信したかった。
フロント側でaxiosを使っていて楽だったのでそれを使おうと思った。結論
const fs = require('fs') const axios = require('axios') const FormData = require('form-data') const uploadImage = async ({ auth_token, imageFilePath }) => { const form = new FormData() const file = fs.createReadStream(imageFilePath) form.append('image_file', file) const config = { headers: { 'X-AUTH-Token': auth_token, 'X-API-Token': env.API_TOKEN, ...form.getHeaders(), // ← ← ← ← ここ!! }, } const result = await axios.post(env.API_BASE_URL + 'api/v1/images', form, config) }経緯
目的
テスト用の大量のデータをフロント経由で準備するのが面倒だったので、API経由でデータを一括登録するためにNode.jsでスクリプトを作ろうとしました。
最初のコード
const fs = require('fs') const axios = require('axios') const FormData = require('form-data') const uploadImage = async ({ auth_token, imageFile }) => { const form = new FormData() const file = fs.createReadStream(imageFile) form.append('image_type') form.append('image_file', file) const config = { headers: { 'content-type': 'multipart/form-data', 'X-AUTH-Token': auth_token, 'X-API-Token': API_TOKEN, }, } const result await axios.post(env.API_BASE_URL + 'api/v1/images', form, config) }エラー
{ status: 500, statusText: 'Internal Server Error' }なるほどわからん
どつぼにはまりました(1時間)
違いの比較
ちゃんと送信できているフロント側のコードと比較するとRequest Headersがなんか違いました
// Node.jsのヘッダー { "Content-Type": "mutlipart/form-data" }// フロントが送信しているヘッダー { "Content-Type": "content-type: multipart/form-data; boundary=----WebKitFormBoundaryYtLvDL7BwH9NCRJja" }
content-type
消してみた自前で付けている
'content-type': 'multipart/form-data'
消してみましたが駄目。
Request がmultipart/form-data
になってないことによるエラーが発生。{ status: 400, }{ 'Content-Type': 'application/x-www-form-urlencoded', }調べたら情報あった
node.js axios FormData
でググったらバッチリでました。ありがたや。要するに
FormData
が自身の送信用にheader作ってくれるから、それ使えやオラァ!ということです。結論
同一コードでフロント上では問題なかったので混乱しました
最初からググって調べようね(教訓)