いろいろ備忘録

雑記です。

N 実践HTTP 15~ 覚書

URL設計は基本的にモデルを基準にする。単独で操作するケースが少ないモデルは、そのモデルが従属するモデルのURLで行う。例を出すと、試験問題モデルは試験モデルのURLでよい。

 passport.serializeUser( (obj,done) => {} )でユーザオブジェクトをどのようにセッションに埋め込むかを規定できる。例えば省メモリ化するためにIDのみ埋め込むなど。

passport.initialize() middleware not in useとエラーが出た。メッセージそのまま、app.use(passsport.initialize())の前にpassport.authenticate()していたため。

Nodeでオブジェクトのプロパティを全てログ出力したいときは、util.inspect()を使う。引数はバージョンによって違うのでドキュメントを見る。

 npm package.jsonのscriptsのキーでコマンドを定義できる。npm startもそこで定義されている。

supertestによってExpressを起動することなく、routerオブジェクトをテストすることができる。

github-stubなど、OAuthのスタブのライブラリがある。

supertestではget()でGETリクエストして、expectでヘッダやbodyの内容をチェックできる。当然正規表現も使える。

 UUIDとは、全世界で(ほぼ)唯一の文字列。主キーが推測されてはいけないとき等に使える。Sequelizeではこのデータ型が用意されている。

複合主キーの順番は、インデックスによって結果を絞る順番と同じなので、慎重に設計する必要がある。

Sequelizeはsync()でCREATE TABLEする。つまり、外部キー制約に引っかからないために、A→Bという関係がある時はA.sync().then( () => { B.belongsTo(なんたら); B.sync()})のようにする必要がある。

npm start でsync()する場合、当然ターミナルは最後のSQLのログを吐いて、サーバとしての役割をするため終了しない。10分くらい待ってしまった。

UPSERTとは、レコードが存在しない場合はINSERT,存在する場合はUPDATEを行うこと。

router.get('/new', checker, (req, res, next) => {
 

このcheckerは別のrouter。checkerを通してから処理できるので、ログインが必要なページにルーティングするとき、このように記述してcheckerに認証処理等をさせる。checkerは委譲されたルーティングを元に戻さないとダメなので戻認証処理の後にnext()が必要。

slice(0, 255)によって255文字以下にする。

.map((b) => { return { a:b , c-key:1 }  })とすれば、DBで従属側に外部キーを一気につけられる。

 sequelizeは基本的にSQLインジェクションが不可能だが、where句で複雑なものが使いたい時に、条件を文字列で書くと可能になってしまう。そこはちゃんとエスケープかプレースホルダを使う。

レスポンスヘッダのX-Frame-Options:SAMEORIGINにより、外部サイトからアクセスできないようになる。

オープンリダイレクタ脆弱性とは、http://hoge.com/login?to=http://危険.xyzというリンクによってhttp://危険.xyzにリダイレクトするようなこと。
ログイン前にログインが必要なページに行く→ログインする→ログイン後にそこにリダイレクト のようなケースでは、ログインページでクエリを基にcookieにリダイレクト先を書いておき、ログイン後にそれを基にリダイレクトする。
そのときオープンリダイレクタ脆弱性をもつ可能性がある。対策はドメイン名より後のパスのみをクエリにし、かつcookieに書き込む前にスキーマが含まないことを確認すること。

<img src="URL"のURLは画像じゃなくても良い。画像が動的に生成されるページもあるので拡張子は考慮されないため。つまり勝手にGETできるということ。

CSRFとはjsで勝手にログインしているAmazonなどに向けてPOSTすること。トークンと呼ばれるセッションIDに紐付いた推測不可能な文字列(ハッシュで作れる)をhiddenで埋め込み、一緒にPOSTすることによって防ぐことができる。組み込みのモジュールを使っておけば問題ない。

Bootstrap Form おさらい - Qiita

N 実践HTTP ~14 覚書

PORT=8000 npm startはLinuxでの書式。
Windowsではset PORT=8000 & npm start とする。このsetコマンドとは、実行中の環境(プロンプト)でのみ有効な環境変数を設定するコマンド。「&(アンパサンド)」はコマンドの区切り文字。複数のコマンドを連続で実行できる。

 

ExpressはデフォルトではX-powered-by ヘッダにExpressを書き込む。
つまり閲覧者にExpressを使用していることを知られてしまう。
helmetモジュールによってこれを送信しないように設定できる。
他にもいくつかセキュリティに有用なHTTPヘッダがあり、helmetによって有効化される。
Node.jsのセキュリティ・チェックリスト | プログラミング | POSTD
なお、X-powered-byを隠したいだけならhelmetを使用せずapp.disable('x-powered-by');でも良い。

express実践入門 · GitHub

 

router.get('/', function(req, res, next) {});のnextはnext()のように使う。次に一致する、このルートの次に対象範囲が広いルートに処理を渡す。

Express - node Webフレームワーク | 日本語ドキュメンテーション

 

Applicationクラスのuseメソッドは、新しくrouterオブジェクトやミドルウェアを登録したり、設定をしたりするもの。設定にはテンプレートのパスやテンプレートエンジン、ログなどがある。

app.get('env')で、開発環境かリリース環境か取得できる。

 Node.jsでは、エンコードなどCPUに負荷がかかる処理はイベントループを妨げるためしてはいけない。Scalajavaなどマルチスレッドの処理系に委譲すべき。

log(2);やlog(4);をconsole.log('2');に置換したい時、検索 log\((\d)\) 置換 console.log('$1')とする。数字の部分を置換後に使うため、カッコでくくった。置換後は$1,$2のように何番目か指定して使用する。

mochaでのテスト

  1. mochaはtest/test.jsを参照する。mochaのコマンドは長いので、npm testだけでmochaが実行されるようにpackage.jsonのscriptsを編集
  2. test/test.jsにテスト用のコードを書く

webpack

  • webpackとは、JSのモジュールを一つのファイルにまとめるもの。通信量削減や名前空間の隠蔽などメリットがある。
  • entry.jsはルートとなる。javaで言うとMain.java。ここから参照を始める。
  • JSを変更したらwebpackでビルドという手順。Nodeが起動している間に変更されたら自動でビルドするという設定もある。
  • uglify(JSの圧縮)も設定で可能。

 JQueryを使用したjsを最初に読み込んでしまうと、HTMLが読み込まれていないためにconst para = $('#id')が取得できない場合がある。最後に書くか、遅延読み込みか、何らかの策を講ずる必要がある。

X-Requested-withによってajaxのリクエストか判定できる。

 

N HTTPサーバ 22~26 覚書

PostgresSQLのCLI

psql -U ユーザ名 でログイン
\c データベース名 で使用するDBを決定
その後は普通にSQLを実行できる

!! Visual Studio CodeにはIDEAのキーバインドにする拡張機能がある!!

Number.MAX_SAFE_INTEGERによって、jsで正確に扱える範囲で最大の整数値が得られる。

cookieのexpiresはDateオブジェクトを設定する。

サイトのユーザにCookieでランダムの識別子(トラッキングID)を発行するものをトラッキングクッキーと言う。トラッキングIDでデータを紐付けることにより、匿名でも閲覧や書き込みの行動記録を得られるようになる。しかしCookieなので削除や改ざんができるため信用性に乏しい。

 

switch (req.method) {
case 'POST':
req.on('data', (data) => {
const decoded = decodeURIComponent(data);

これはPOSTで受信したデータをデコードする処理。
decodeURIComponent()する理由は「=」などの記号や日本語などが来ても扱えるようにするため。
関数名にURIがついているが、URI以外にも使える。
decodeURIという似たような関数があるが、これは記号をデコードしない。今回はイコールまで文字列比較を行いたい。よってdecodeURIComponent()が選ばれた。
最終的にdecodedの値はdata=somethingのようになる。

 

faviconのContentTypeは image/vnd.microsoft.icon となる。当たり前だがhtmlではない。

 

windowsにpostgreSQLのインストール

  1. 公式サイトからインストーラをダウンロードする。
  2. 普通にインストールする。スタックビルダがどうたらはしない。
  3. 環境変数にbinディレクトリを設定する。
  4. コマンドプロンプトpsql -U postgresを入力、パスワードも入力し、ログインできることを確認。

Node.jsのイベントループ

「for やめろ」またはイベントループと nextTick() - Block Rockin’ Codes

Node.jsはイベントのキューにイベントがあったら処理をする。

そしてイベントのキューにタスクがあるかどうかの確認でループし続けている(=ノンブロッキング)

イベントのキューにはIO用、setTimeout/setInterval用、setImmediate用、などの種類がある。この円の上にあるキューはlibuvで実装されていて、真ん中はnode.jsのもの。

f:id:namaza:20170807234912p:plain

Timers, Immediates and Process.nextTick— NodeJS Event Loop Part 2

 

流れとしては、キューを移動する前にnext tickキューを確認し、それが空になるまで処理し、空になったら移動する。タスク数の制限がないので注意が必要。
つまり、

開始
→next tick
→timers
→next tick
→IO
→next tick
→immediates
→next tick
→close handle

のように、毎回next tickをはさんで遷移する。

next tickにはタスク数の制限がないので、このコードは絶対に最後に「!」が出力される。こういった処理によってイベントループが回らなくなってしまう。

for (let i = 0; i < 10000; i++) {
process.nextTick( () => console.log('_'));
}

setImmediate( () => console.log('!'));

git cloneで失敗する時 windows

Warning: Permanently added the RSA host key for IP address 'IPアドレス' to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

とエラーが出た。

Windowsでは、ユーザフォルダ/.ssh/id_rsa.pubが公開鍵のファイルなので、これをGitHub側に設定(コピペ)する。

N HTTPサーバ ~21 覚書

nodegrind -o app.cpuprofile ファイル名 でパフォーマンスの測定を行い、結果出力を行う。出力されたファイルはChromeJavascript profileで読み込める。

echoのリダイレクト(閉じカッコ一つ)はファイルがない場合新規作成する。

 

git cloneで失敗する時 windows - いろいろ備忘録

node.jsのhttpモジュールにおいて、エラーはイベントで発生する。すなわち

http.createServer((req, res) => {
 
}).on('error', (e) => {
}).on('clientError', (e) => {
});

のように、イベントを処理する「on」で、errorイベントを処理することになる。

node index.js 2>&1 | tee -a tmp.log

  1. nodeがログを出力する
  2. 2>&1によって、エラー出力が標準出力になる。
    これがないと次のteeにエラー出力が渡せない。
  3. teeコマンドが標準入力を標準出力とファイルの両方に出力する。
  4. 結果、コンソールとファイルの両方に、info,warn,errorログの全てが出力される。

 curlコマンドでは、-d オプションでPOSTできる。
-d 'message=testMessage' のように、POSTするデータがkey = valueの形になることに注意。HTMLでformにnameが必要なことと同じ。

Node.jsのイベントループ - いろいろ備忘録

レスポンスをStreamのpipe(出力先)で返せる。ストリームなのでメモリが節約できる。入力側で出力側のend()を呼ぶため、res.end()がいらないが、pipe()のオプションで変更できる。

 

  const rs = fs.createReadStream("./form.html");
            rs.pipe(res);
            let i = 0;
            let fc = ()=>{
                if (++i > 2) {
                    rs.unpipe(res);
                    res.end();
                }else{
                setImmediate(fc);
                }
            };
            setImmediate(fc);

上記コードはイベントループごとにfcが実行され、4回目のイベントループでパイプを解除し、end()する。
イベントループ1回目 次のイベントループにfcを登録する i == undefined
イベントループ2回目 fcを実行し、fc内で次のイベントループにfcを登録 i==1
イベントループ3回目 同上 i==2
イベントループ4回目 fcを実行するが、i==3となるのでパイプ解除とend()する
肝となるのは、実行するとHTMLが何も返らないこと。
ストリームから最初のデータが送出される前にunpipe()されるため。
イベントループの制限を4回ではなく10回とかにすると中途半端なHTMLが返る。ストリームの途中でunpipe()されるため。
1000とかにすると、完全にストリームが出力し終わった後となるので、おそらく全てのHTMLが出力されている。

 

node.jsのBASIC認証に使うauth.basicの第二引数

(username, password, callback) => {
//このcallback()は引数で渡されている。アクセスを許可するかどうかのbool値を引数にとる。
//いつもは無名関数を渡す事が多いが、これはその逆バージョンになっている。
callback(username === 'guest' && password === 'xaXZJQmE');
}

 

BASIC認証BASE64エンコードしているだけなので盗聴されるとバレる。

BASIC認証では、401 Unauthorizedを返すことでログアウトが可能。

Cookieは毎回リクエストヘッダに挿入して送信されている。あまり肥大化するとサーバやネットワークに負荷がかかるため容量に制限がある。また、BASIC認証も毎回送信されている。HTTPはステートレスなため。

req.header.cookieは文字列。indexOf()やsplit()を使って目的のものを取り出す。

 

Anatomy of an HTTP Transaction | Node.js

 req.on('data',(chunk)=>{})のイベント「data」は、イベントループごとに送られてきたデータが存在する時実行されるが、断片的なものであっても実行されるので、大きなデータや低速で送られてくる場合、すなわち一回のイベントループで全てのデータが来なかった場合はこれだけでは処理が難しい場合がある。普通は、イベント「data」では受信したバイト配列をappend()していき、受信し終わったときにイベント「end」がemitされるので、それでconcat()してtoString()などする。