@ledsun blog

無味の味は佳境に入らざればすなわち知れず

Form で遊ぶために対抗サーバーを作って公開した

背景

HTML fromを新人に説明しようとしました。 うまく説明できませんでした。 つまり、よく分かっていません。

ドキュメントを読んで言葉で理解し、 パラメーターを変えながら実際に動かして、心で理解したいです。 しかし、formは対抗するサーバーがないと試しづらいです。*1

form-exercise

formで送信したHTTPリクエストの内容(メソッド、クエリ、ボディ)を表示するサーバーを作りました。

配置先サイト

github

使い方

こういうformから

<form action="https://form-exercise.herokuapp.com/">
    <input type="submit" value="submit">
    <input type="text" name="name" value="1">
</form>

submitすると https://form-exercise.herokuapp.com/?name=1 を表示します。

postメソッドも受け付けます。

実装

connectを使って作りました。 Node.jsです。Herokuで動いています。

実装時にぶつかった課題

connectの標準middlewareは、どれを使うと今風なのかよく分からない

いつもbody-parserをそのまま使っていいのかで迷う。 いいかげんREADMEのサンプルを動かすと、警告出るの何とかして欲しいものです。

let app = connect()
    .use(bodyParser.urlencoded({
        extended: false
    }))

て、bodyParser は extended オプションを指定して使えばいいようです。

renderの共有

middlewareとして実装したい

render関数(データに表示用テンプレートを適用する)は複数のmiddlewareで共有したい。 それでいて、↓のような共通関数でなく

function render(res, values) {
    let html = `
        <div>Method: ${req.method}</div>
        <div>URL: ${req.url}</div>
        <div>Values: ${JSON.stringify(values)}</div>
    `

    res.end(html)
}

connectのmiddlewareとして実装したい。

connectのmiddleware

connectはmiddlewareを追加して機能を追加します。 middlewareはChain of Responsibilityです。

  1. requestとresponseをmiddlewareからmiddlewareと渡して行きます。
  2. 各middlewareはrequestとresponseの自分が興味がある部分を処理し、
  3. 次のmiddlewareにrequestとresponseを渡します。
結論

ExpressのAPIを真似してresponse に renderメソッドを生やすmiddlewareにしました。

デプロイ時にぶつかった課題

ES6をherokuで動かす方法

nodemon使って実装していました。 nodemonは--exec babel-nodeをつけるだけでbabelが動きます。 そこで調子に乗ってES6で実装したらHerokuでの動かし方で困りました。

gulpで変換

gulpで力技変換。こんな風に

var gulp = require('gulp');
var babel = require('gulp-babel');
var rimraf = require('rimraf');

gulp.task('clean', function(cb) {
    rimraf('./dist', cb);
});

gulp.task('lib', ['clean'], function() {
    return gulp.src([
            'src/lib/get.js',
            'src/lib/post.js',
            'src/lib/render.js'
        ])
        .pipe(babel())
        .pipe(gulp.dest('dist/lib'));
});

gulp.task('app', ['lib'], function() {
    return gulp.src([
            'src/app.js'
        ])
        .pipe(babel())
        .pipe(gulp.dest('dist'));
});

gulp.task('default', ['app']);
twitterで知見を得る

@tgfjtさんありがとうございます。

結論

package.jsonに下を書くだけで動きました

"start": "babel-node app.js"

Herokuもbabelも便利すぎる。神なのでしょうか?

※dependenciesにbabelを追加してください。

その他

全くどうでもいい蛇足情報

セキュリティ面ではノーガード実装です。 せっかくなので<script>alert()</script>投げてみると、次のエラーが出て、スクリプトは実行されませんでした。

The XSS Auditor refused to execute a script in 'https://form-exercise.herokuapp.com/?name=%3Cscript%3Ealert%3C%2Fscript%3E' because its source code was found within the request. The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.

デフォルトでX-XSS-Protectionが有効なようです。 Google Chrome偉い。

*1:世の中にすでに、類似サーバーがあるかは確認していません。調べ方がよくわかりません。教えてください。