Go Revelフレームワーク jQuery非同期処理

概要

Go RevelフレームワークでAjax非同期処理を実装します。

CSRF 対策

以下コマンドにより
RevelフレームワークでCSFR対策する為のライブラリをインストール

1
$ go get github.com/cbonello/revel-csrf
  • app/init.go

ajax実行時にCSRFチェックする為、init.goでのチェックを外すように設定

以下CSRFのFilter設定

1
2
3
4
5
6
func init()
revel.Filters = []revel.Filter{
...
...
csrf.CSRFFilter, // CSRF prevention.
...

conf/routes で実行するAPIのURLはAjax実行時にCSRFチェックする為、
init.goではチェックを対象外とする様に設定

1
csrf.ExemptedFullPath("/api_execute")

View側の設定

  • views/header.html

<head>〜</head> 内にCSRFチェック用ハッシュ値をmeta情報として埋め込みます。

1
<meta name="csrf-token" content="{{ .csrf_token }}">

jQueryファイル

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function setAjaxToken( token ) {
// ajax --- start --------------------------------------------------
$.ajaxSetup({
crossDomain: false,
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", token );
}
}
});
}

$(document).ready(function () {
$(document).on("click", ".ajax_execute", function (event) {
event.preventDefault();

setAjaxToken( postData['_token'] );

var ajaxParamas = {};
ajaxParamas["type"] = "POST";
ajaxParamas["url"] = action;
ajaxParamas["data"] = postData;
ajaxParamas["cache"] = false;
ajaxParamas["dataType"] = "json";

$.ajax(ajaxParamas)
.success( function(res) {
console.log("(^-^) OK")
}).error ( function() {
console.log("(>_<) NG")
});
return false;
})

簡単…とは行ってない気がしますが
CSRF対策ができました。

Go初心者におすすめ本

概要

身の回りであまり Go を積極的にやっている人がいないので
やってみたいなぁ、気になってはいる、
という方に本をおすすめしてみたいと思いました。

この一冊!

以下をチョイスしました!

よかった点

  • 全部で 34 ページ!1 日で読み終わり、逆引きとしても利用できる。(Go のオフィシャルのチュートリアルをまとめてくれてる感じ)
  • Go の成り立ちを簡潔に説明しており、クロスコンパイルや並列処理サポートなどがあり Go の使いどころがわかる。
  • ちょうど「Web API デザインの鉄則」という特集があり、API 開発にはちょうど良い内容の一冊だった。

特に本を紹介して自分にお金が入ることはないので
斜めから見ずにまず本見てみてください ♪

Go を使いたくなる記事

JSON シリアライズし秒間のレスポンス回数測定

以下 Qiita 記事でまとめてくれていました。

「最速」フルスタック Web フレームワーク「revel」の紹介

個人的に好きな所

  • while や do/while 、参考演算子がなく for のみ、とか冗長なコーディングを許さない
  • gofmt でフォーマット化してくれる。いつもコミット前にやってます。
  • ライブラリ増えてる。 Python のpip installみたく go getでインストール可。
  • ネイティブなのでアプリケーションが大きくなってもさほど遅くならない。

以上
Gopher とお話できる機会が増えると何よりです。

go get で 「exec: "bzr": executable file not found in $PATH」エラー対策

結論

bzrモジュールインストールした後、再度go getして問題なく動作しました。

1
# yum install -y bzr

概要

EC2のCentOS7で
以下のように go get した際にbzrが見当たらないというエラーが発生した。

1
2
3
4
5
$ go get launchpad.net/goamz/aws

[centos@ip-xxx-xx-xx-xx src]$ go get launchpad.net/goamz/aws
go: missing Bazaar command. See http://golang.org/s/gogetcmd
package launchpad.net/goamz/aws: exec: "bzr": executable file not found in $PATH

ちょこっとしたつまづきでした。

ちなみに

bzrはgitと同様、分散バージョン管理システムです。

今回インストールしようとしたPackageがBazaarで管理していたから必要になったのでしょう。

以下参照
Bazaarユーザーリファレンス

Golang Revelフレームワークエラー 「server.go:1775: http: TLS handshake error from 127.0.0.1:36799: tls: first record does not look like a TLS handshake」対応

結論

[prod]モード以外で http.ssl = true とし起動すると発生するエラーでした。
その為、[prod]以外では http.ssl = false として起動することとしました。

概要

テスト環境で app.conf にて[test]モードを追加し
そこでオレオレ SSL 証明書作成して https リンクの動作確認をしようとしてました。

ですが、起動こそするものの一向にアクセスできず汗

dev モードではアクセス出来るのでその差分を見たところ、上記の結論に至りました。

エラー内容

revel 起動し url にアクセスすると以下のような TLS ハンドシェイクができずアクセスできない状況になる。

1
2
3
4
5
6
7
$ revel run myapp test

...
...

INFO 2015/08/19 14:48:38 harness.go:165: Listening on :9000
2015/08/19 14:48:40 server.go:1775: http: TLS handshake error from 127.0.0.1:36799: tls: first record does not look like a TLS handshake
go-sql-driver/mysqlでcreated_at (datetime) がUTCで登録されてしまう件

go-sql-driver/mysqlでcreated_at (datetime) がUTCで登録されてしまう件

環境

  • go-sql-driver/mysql version 1.2

結論

以下のように parseTime=trueloc=Asia%2FTokyoを設定する。

1
db, err := sql.Open("mysql", "user:passward@/dbname?parseTime=true&loc=Asia%2FTokyo")

loc=xxxxの指定がない場合、localが指定され、
datetime に time.Now()を指定して INSERT しても
UTC 時間に書き直されてしまう。

ちょっとハマりました。

Golang Revelフレームワーク ホットデプロイ方法

概要

Revel Official サイトにあるデプロイ方法を検証しました。

Revel Deployment

  1. ローカルでアプリをビルドしサーバにコピーする
  2. サーバーで更新したコードを pull し、ビルド・起動する
  3. Heroku を利用しデプロイ管理する

1. ローカルビルド

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# アプリを実行しテストする
$ revel run import/path/to/app

# パッケージ化
$ revel package import/path/to/app
Your archive is ready: app.tar.gz

# 対象マシンへコピー
$ scp app.tar.gz target:/srv/

# ターゲットマシンで起動
$ ssh target
$ cd /srv/
$ tar xzvf app.tar.gz
$ bash run.sh

開発しているアーキテクチャと同じ環境へデプロイする場合、
もしくは go インストールを設定し、デフォルトで希望するアーキテクチャへビルドするための唯一の方法です。

2. 追加デプロイメント

フルセットアセット付きの静的にリンクされたバイナリが巨大になる可能性があるので、
追加デプロイをサポートしています。

1
2
3
4
5
6
7
8
# アプリを一時ディレクトリにビルド
$ revel build import/path/to/app /tmp/app

# サーバのhomeディレクトリにその一時ディレクトリにrsync
$ rsync -vaz --rsh="ssh" /tmp/app server

# サーバーに接続しアプリを再起動
...

rsync は ssh でのコピーをサポートしているので、以下のように複雑にはなりますがデプロイ可能です。

1
2
# カスタム証明書、ログイン名、対象ディレクトリを指定しrsync
$ rsync -vaz --rsh="ssh -i .ssh/go.pem" /tmp/myapp2 ubuntu@ec2-50-16-80-4.compute-1.amazonaws.com:~/rsync

3. サーバでビルド

この方法はバージョンコントロールシステムに依存します。
Go をインストールしているサーバーが必要です。
その代わり、クロスコンパイルを回避することができます。

1
2
3
4
5
6
7
8
$ ssh server
... install go ...
... configure your app repository ...

# appディレクトリに移動し pullしサーバー起動する
$ cd gocode/src/import/path/to/app
$ git pull
$ revel run import/path/to/app prod

総評

現在社内では、1. ローカルビルド のデプロイ方法を選択しています。

2. 追加デプロイメント は、再起動時の瞬断が懸念されます。
大規模アクセスを捌く目的で利用する Go には向いていないと思います。

3. サーバでビルド は、運用方法にもよりますが、
本番環境でコンフリクトが起きてしまったらコンパイルもストップしてしまう懸念があります。

1. ローカルビルド方法を Jenkins で管理して運用しており
現状特に問題ないです。

Jenkins の設定等まとめてから公開したいと思います。