- 投稿日:2021-03-02T21:53:46+09:00
Cookieを使った認証機能を実装しようとしてCORSでどハマりした時のメモ
前提
- フロントエンド:Nuxt.js → http://localhost:3000
- バックエンド:Node.js → http://localhost:4000
- universal-cookieを使う
やりたかったこと
- サーバーで発行されたcredential情報をcookieとして保存すること
- cookieに保存されているcredential情報をサーバーに送付して、それを元に認証機能を実装すること
はまったこと
- クライアントからのリクエストに対して、サーバー側からのレスポンスに
Set-Cookie
ヘッダーを付与することは出来て、ブラウザのdeveloper toolでもSet-Cookie
ヘッダーがレスポンスにあることを確認出来ているのに、クライアントでcookieがセットされない。原因
- 原因はCORSの設定。
解決のために参考したリンク(ほんとまじでありがとうございます!)
await axios.get('apiのエンドポイント', { withCredentials: true });
- Access-Control-Allow-Credentials - MDN Web Docs
- Access-Control-Allow-Origin - MDN Web Docs
- cors - npm package
import cors from 'cors'; const app = express(); app.use(cors({ origin: true, credentials: true }));
- 投稿日:2021-03-02T20:57:47+09:00
Nuxt.jsでscss導入しようとしたらエラッた
開発環境
macOS: 10.15.7
node: 14.15.3
npm: 6.14.9再現方法 (2021.03.02時点)
npx create-nuxt-app projectName-xxxx
上記で諸々をインストール後に、下記でscssに必要なパッケージをインストール
npm install --save-dev node-sass sass-loader @nuxtjs/style-resources
そしてvueファイルの
<style> ... </style>を、↓に書き換える
<style lang="scss"> ... </style>そして、
npm run dev
を実行すると下記エラーERROR Failed to compile with 1 errors friendly-errors 20:33:55 ERROR in ./pages/index.vue?vue&type=style&index=0&lang=scss& friendly-errors 20:33:55 Module build failed (from ./node_modules/sass-loader/dist/cjs.js): friendly-errors 20:33:55 TypeError: this.getOptions is not a function at Object.loader (/Users/xxxx/node_modules/sass-loader/dist/index.js:25:24)原因
Nodeと下記パッケージのバージョンがうまく噛み合っていないよう。
この段階でインストールされているパッケージのバージョンは↓package.json
"node-sass": "^5.0.0", "sass-loader": "^11.0.1",解決方法
node-sass
とsass-loader
のバージョンを下げたらエラー解消した解決方法の詳細
1. まずは
node-sass
のバージョンを下げてみる
npm uninstall --save-dev node-sass
でアンインストールして、
npm install --save-dev node-sass@4.14
でバージョン指定して再インストール
npm run dev
実行 → エラー解消せず(先述のエラー発生)2.
sass-loader
のバージョンも下げてみる
npm uninstall --save-dev sass-loader
でアンインストールして、
npm install --save-dev sass-loader@10.1.0
でバージョン指定して再インストール
npm run dev
実行 → エラー解消!!所感
エラー解消してよかった〜
補足
今回のエラーに関しては、ググった感じでは他に起因するケースもあるようです。
本記事は原因の一つとしてご参考までにmm
- 投稿日:2021-03-02T16:48:47+09:00
【Node.js】Expressでセッション機能を使う方法
プログラミング勉強日記
2021年3月2日
セッション機能とは
Webサーバーとブラウザの間で続けて通信を行うために必要な機能で、サーバー側でクライアントの状態を管理する方法である。セッションを利用することで、同じクライアントからサーバーに何回アクセスされたかなどを管理することができる。
Express sessionの使い方
express-sessionモジュールをインストールして、
--save
オプションを使用することでインストールの情報を保存できる。$ npm install --save express-sessionそうすると、package.jsonにexpress-sessionが追加される。
package.jsoon"dependencies": { "ejs": "^2.6.1", "express": "^4.16.4", "express-session": "^1.15.6" }sessionの基本構文
まず、インスタンス名で指定したオブジェクトに対して
use
でセッションを使用すると宣言する。session
でセッション処理を行うことを指定して、値のところで具体的にどのような処理を行うか指定する。インスタンス名.use(session({ 設定項目: '値', }))参考文献
セッション機能について
セッションを扱う!express-sessionを利用する方法【初心者向け】
express-sessionでセッションを利用する[Express][node.js]
- 投稿日:2021-03-02T10:02:57+09:00
Node.jsでcsvファイルを読み書きする
はじめに
node.jsでcsvを読み書きしたい時があったので,備忘録としてまとめようと思い,この記事を書きました。
streamを使ったやり方など,色々と方法があったのですが,今回はfs.readFileSync
とfs.writeFileSync
を用いた方法でやってみました。大まかな流れ
- 必要なパッケージのダウンロード
- 読み込むcsvファイルの作成
- 実行ファイルの作成
- 実行
必要なパッケージのダウンロード
今回は,
csv
というモジュールを使用しますので,以下コマンドを使用してダウンロードします。$ npm install --save csv
--save
: package.jsonのdependenciesに追加される読み込むcsvファイルの作成
先頭の行に,カラム名を入れておきます。
input.csvname,age,gender taro,30,man jiro,28,man hanako,20,woman実行ファイルの作成
実行ファイルの完成形
input.csv
というcsvファイルを読み込み,行を追加してoutput.csv
という名前で出力するコードになっています。sample.js// file system モジュールを読み込む const fs = require('fs'); // csv モジュールの内,必要な機能を読み込む const parse = require('csv-parse/lib/sync'); const stringify = require('csv-stringify/lib/sync'); // csvファイルを読み込む const inputData = fs.readFileSync('./input.csv', { encoding : 'utf8' }); // 先頭行をcolumnとして扱い,csvデータをparse const parsedData = parse(inputData, { columns : true }); // 行を追加 parsedData.push({ 'name': 'saburo', 'age': '25', 'gender': 'man'}); // オブジェクトのプロパティを先頭行に記述し,csvデータに変換 const outputData = stringify(parsedData, { header : true }); // csvファイルを出力 fs.writeFileSync('output.csv', outputData, { encoding: 'utf8' });以下で詳細に説明します。
モジュールの読み込み
sample.js(一部)// file system モジュールを読み込む const fs = require('fs'); // csv モジュールの内,必要な機能を読み込む const parse = require('csv-parse/lib/sync'); const stringify = require('csv-stringify/lib/sync');実装に必要なモジュールを読み込みます。(csv-parse と csv-stringfy については,後ほど詳しく説明します。)
csvファイルを読み込む
sample.js(一部)// csvファイルを読み込む const inputData = fs.readFileSync('./input.csv', { encoding : 'utf8' });fsモジュールを用いて,
input.csv
を読み込みます。
今回は,オプションで文字コードをUTF-8
と指定しています。csvファイルをオブジェクトに変換
sample.js(一部)// 先頭行をcolumnとして扱い,csvデータをparse const parsedData = parse(inputData, { columns : true });
fs.readFileSync
でcsvファイルを読み込むと,以下のように単なる文字列として保存されます。inputDataの中身name,age,gender taro,30,man jiro,28,man hanako,20,woman
これを,javascriptで操作しやすくするためにオブジェクトの形式に変更するのが, csv-parse です。
columns : true
というオプションをつけることによって,csvファイルの先頭行を,オブジェクト変換後のプロパティとして扱います。parsedDataの中身[ { name: 'taro', age: '30', gender: 'man' }, { name: 'jiro', age: '28', gender: 'man' }, { name: 'hanako', age: '20', gender: 'woman' } ]
末尾に行を追加
sample.js(一部)// 行を追加 parsedData.push({ 'name': 'saburo', 'age': '25', 'gender': 'man'});オブジェクトをcsvデータに変換
sample.js(一部)// オブジェクトのプロパティを先頭行に記述し,csvデータに変換 const outputData = stringify(parsedData, { header : true });csv-stringify は, csv-parse とは逆に,javascriptのオブジェクトをcsvファイルとして出力するための文字列に変換するモジュールです。
変換されたデータは,以下のような中身になっています。outputDataの中身name,age,gender taro,30,man jiro,28,man hanako,20,woman saburo,25,man
csvファイルを出力
sample.js(一部)// csvファイルを出力 fs.writeFileSync('output.csv', outputData, { encoding: 'utf8' });
fs
モジュールを用いて,output.csv
という名前でcsvファイルを出力します。実行
$ node sample.jsoutput.csvname,age,gender taro,30,man jiro,28,man hanako,20,woman saburo,25,man参考
- 投稿日:2021-03-02T09:24:22+09:00
Express.jsでファイルダウンロード
Express.jsで画像などのファイルをダウンロードする方法です。
本記事の内容は以下のドキュメントに書かれている内容の説明になります。
https://expressjs.com/ja/api.html実行環境
express.js 4.17.1
MacOS 10.15.7方法その1 簡易的な方法
import express from 'express'; export const router: express.Router = express.Router() router.get('/download', (req, res) => { res.download('images/どね.jpg') })
download
メソッドを使います。ファイルパスを引数に取ることになるので、一度ファイルをストレージのどこかに置く必要があります。すでにBuffer形式になっている場合は少し面倒ですね。
方法その2 headerに指定
import express from 'express'; import fs from 'fs/promises' export const router: express.Router = express.Router() router.get('/set', async (req, res) => { const img = await fs.readFile('images/どね.jpg') const fileName = encodeURIComponent('どね.jpg') res.set({'Content-Disposition': `attachment; filename=${fileName}`}) res.status(200).send(img) })レスポンスのヘッダーを直接指定します。
Content-Disposition
のattachment
を指定することでブラウザ側でダウンロードファイルであることを認識してくれます。
それ以外にも以下の処理が必要になります。
- Bufferファイルを一度読み込んでbodyに入れる
- 日本語ファイル名の可能性がある場合はファイル名にエンコードをかける
filenameとfilename*の違いについて
引数の filename と filename* の違いは、 filename* が RFC 5987 で定義されているエンコーディングを使用するという点のみです。単一のヘッダーフィールドの値に filename と filename* の両方が存在する場合は、両方が解釈できる場合、 filename* が filename よりも優先されます。
方法1では
filename*
が自動で使われて、方法2ではどちらも指定できます。
方法1 方法2 いくつかのブラウザで試しましたがすべて
filename*
を認識できていました。使える文字もこちらのほうが多いようです。あえてfilename
を使う必要はなさそうです。もし使えないブラウザがあったら教えていただきたいです。試したブラウザを以下に置いておきます。
ブラウザ バージョン 対応状況 Chrome 88 ○ FireFox 88 ○ Microsoft Edge 88 ○ Internet Explorer 11 ○ まとめ
たいていはフレームワークに乗っかった方が後々困ることもないので方法1推奨です。
修正がかかったらフレームワーク側を直せば良い話ですし。
- 投稿日:2021-03-02T00:09:58+09:00
TypeScript(Node.js)でテキストファイルを指定行数ごとに分割する
テキストファイルを分割したいときってありますよね。
例えばSQLのINSERT INTO hoge VALUES
に続く行が数万行ある時とか (そんなにない)個人的に上記をやりたいタイミングがあって、npmでいい感じのモジュールを探したんですが
意外とテキストファイルを「指定した行数で」区切ってくれるやつが無かったので泣く泣く自分で作りました。あ、Nodeです。
Streamで順次処理してるので、でっかいファイルでもヒープアウトしないはず!
Usage
hoge.tsimport { FileSplitter } from "path/to/file-splitter" // your-file.txtを100行ごとに分割する const fileSplitter = new FileSplitter("/path/to/your-file.txt", 100) // 分割開始! fileSplitter.start()御託は良いからコードを見せろ
file-splitter.tsimport fs from "fs" import path from "path" import readline from "readline" export class FileSplitter { private maxLines: number private identifier = 0 private curLine = 0 private lineReader: readline.Interface private currentWriteStream: fs.WriteStream private outputPath: string constructor(readFrom: string, maxLines = 500) { // 分割したファイル群を保存する先のディレクトリを作り、そのpathを保存 this.setOutputDir(readFrom) this.maxLines = maxLines // 最初のWriteStreamを作っておく this.replaceWriteStream() // readlineに指定ファイルのReadStreamを食わせて行リーダーを作る this.lineReader = readline.createInterface({ input: fs.createReadStream(readFrom) }) } start() { this.lineReader .on("line", (line) => { // 現在の行数を保持 (1 ~ 指定行数 + 1までの値を取る) this.curLine++ // ここ、もう少しうまくやりたかった人生だった const isOn = this.curLine === this.maxLines const isOver = this.curLine > this.maxLines if (isOver) { // 指定行数を超えたら新しいファイル向けのWriteStreamに切り替え、行数を1にリセットする this.replaceWriteStream() this.curLine = 1 } if (isOn) { // そのファイル最後の行は改行無しにしている (が、例えば100行のファイルを30行とかで区切られると、最後のファイルには改行が入っちゃう。めんどくさくてこれ以上考えなかった) this.currentWriteStream.write(line) } else { this.currentWriteStream.write(`${line}\n`) } }) .on("close", () => { // 一応掃除する this.closeWriteStreamIfExists() console.info("Done!") }) } private setOutputDir(readFrom: string) { const extension = path.extname(readFrom) const fileName = path.basename(readFrom, extension) const splitFileBaseDir = `${path.dirname(readFrom)}/split-files` this.outputPath = `${splitFileBaseDir}/${fileName}` if (!fs.existsSync(splitFileBaseDir)) { fs.mkdirSync(splitFileBaseDir) } if (!fs.existsSync(this.outputPath)) { fs.mkdirSync(this.outputPath) } } private replaceWriteStream(): void { this.identifier++ this.closeWriteStreamIfExists() const writeTo = `${this.outputPath}/file_${this.identifier}.txt` console.info(`Start writing to ${writeTo}.\n`) this.currentWriteStream = fs .createWriteStream(writeTo) } private closeWriteStreamIfExists() { if (this.currentWriteStream) { this.currentWriteStream.close() } } }まとめ
readline標準モジュールにたどり着くまでの人生を無駄にした。
Streamをちゃんと考えて使ったことあんまりなかったのでちょっと楽しかった。