Symfoware

Symfowareについての考察blog

Riot ajaxで取得したjsonデータをテーブルに表示する(axios使用)

lua nginx moduleでデータベースにアクセスし、json形式のデータを返却することができました。
lua nginx moduleからMariaDB(MySQL)に接続する(lua-sql-mysql)

Riotで取得したjsonを表示してみようと思います。


axios



Riotにajax通信を行う機能はないので、別途ライブラリを使用することにしました。
こちらを参考に「axios」を使ってみます。
superagentとaxiosの使い分け
https://github.com/mzabriskie/axios

CDNを使うことにしました。
https://cdnjs.com/libraries/axios



json形式のデータ



lua nginx moduleからMariaDB(MySQL)に接続する(lua-sql-mysql)
こちらで使ったluaをそのまま使用することにしました。


  1. local driver = require 'luasql.mysql'
  2. env = assert (driver.mysql())
  3. con = assert (env:connect('sample', 'root', 'P@ssw0rd', 'localhost', 3306))
  4. -- 接続文字コードを変更
  5. assert (con:execute('SET NAMES utf8mb4'))
  6. -- データをを取得
  7. result = {}
  8. cur = assert (con:execute("SELECT id, value from t"))
  9. row = cur:fetch ({}, "a")
  10. while row do
  11. local copy_row = {}
  12. for field in pairs(row) do
  13. copy_row[field] = row[field]
  14. end
  15. table.insert(result, copy_row)
  16. row = cur:fetch (row, "a")
  17. end
  18. cur:close()
  19. con:close()
  20. env:close()
  21. -- テーブルをjsonに変換
  22. local cjson = require "cjson"
  23. json_text = cjson.encode(result)
  24. ngx.say(json_text)




テーブルの内容をそのまま返します。


nginxの設定ファイルの抜粋はこのようになりました。


    root /var/www/html;

    location /api {
        lua_code_cache off;
        default_type 'application/json';
        content_by_lua_file /var/dev/lua/sample.lua;
    }
    
    location / {
        try_files $uri $uri/ =404;
    }



/apiでアクセスされた時はluaを実行。
それ以外は、/var/www/htmlにあるファイルを表示します。


Riot + axiosを記載するhtmlファイルは、/var/www/html/index.htmlに配置します。


  1. <!doctype html>
  2. <html lang="ja">
  3.     
  4. <html>
  5. <head>
  6.     <meta charset="UTF-8">
  7.     <title>Riot + axios</title>
  8.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  9. </head>
  10. <body>
  11.     <!-- ここにタグの内容を反映 -->
  12.     <my-tag></my-tag>
  13. </body>
  14. <!-- ここからRiotプログラム -->
  15. <!-- カスタムタグ -->
  16. <script type="riot/tag">
  17. <my-tag>
  18. <h3>ボタンクリックでデータ取得</h3>
  19. <div><input type="button" value="追加" onclick={ add }></div>
  20. <table border="1">
  21.     <thead>
  22.      <tr>
  23.         <td>id</td><td>value</td>
  24.      </tr>
  25.     </thead>
  26.     <tbody>
  27.     <tr each={ items }>
  28.         <td>{ id }</td>
  29.         <td>{ value }</td>
  30.     </tr>
  31.     </tbody>
  32. </table>
  33. var self = this;
  34. self.items = []
  35. add(event) {
  36.      axios.get('/api')
  37.         .then(function (response) {
  38.             self.items = response.data
  39.             self.update()
  40.         })
  41.         .catch(function (error) {
  42.             console.log(error)
  43.         });
  44. }
  45. </my-tag>
  46. </script>
  47. <!-- マウント -->
  48. <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.1/axios.min.js"></script>
  49. <script src="https://cdnjs.cloudflare.com/ajax/libs/riot/3.4.0/riot%2Bcompiler.min.js"></script>
  50. <script>
  51. riot.mount('my-tag')
  52. </script>
  53.     
  54. </html>



データが再描画されなくて悩みましたが、こちらが参考になりました。
Riot.jsでAjaxを使った非同期通信について


初期状態

742_01.png

ボタンクリック後

742_02.png


ちゃんとデーブルの内容が更新されました。

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/04/09(日) 23:16:22|
  2. Lua
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

lua nginx moduleでMessagePackのデータを使用(lua-MessagePack)

lua nginx moduleでいろいろ試しています。
apt-getでDebian 8 + lua nginx moduleの環境構築(nginx-extras)
lua nginx moduleでjson形式のレスポンスを返す(cjson)
lua nginx moduleからMariaDB(MySQL)に接続する(lua-sql-mysql)

jsonの使い方に続き、MessagePackが使えるか調べてみます。


lua-MessagePackとluarocks



これでMessagePack形式のデータが扱えそうです。
lua-MessagePack

インストールにはluarocksを使うのが楽そう。
まず、aptでluarocksをインストールします。


# apt-get install luarocks



luarocksでlua-messagepackをインストール。


# luarocks install lua-messagepack
Installing https://rocks.moonscript.org/lua-messagepack-0.5.0-1.src.rock...
Using https://rocks.moonscript.org/lua-messagepack-0.5.0-1.src.rock... switching to 'build' mode
Updating manifest for /usr/local/lib/luarocks/rocks
lua-messagepack 0.5.0-1 is now built and installed in /usr/local (license: MIT/X11)



インストールできた模様。


nginxの設定ファイル(/etc/nginx/sites-available/default)の抜粋はこうなります。


    location / {
        lua_code_cache off;
        default_type 'application/octet-stream';
        content_by_lua_file /var/dev/lua/sample.lua;
    }




動作確認用に用意した/var/dev/lua/sample.lua


  1. local mp = require 'MessagePack'
  2. value = { true, { foo = "bar" } }
  3. mp_value = mp.pack(value)
  4. ngx.say(mp_value)




packでmessagepack形式に変換してくれます。
ブラウザで確認してみると、こんな表示になりました。

741_01.png



クライアントをPythonで記載してみます。
PythonでMessagePackを使用して、Mapのシリアライズと復元

pipでmsgpack-pythonをインストール。


$ sudo pip install msgpack-python




サンプルはこうなりました。


  1. # -*- coding:utf-8 -*-
  2. import urllib2
  3. import msgpack
  4. f = urllib2.urlopen('http://192.168.1.104/')
  5. packed = f.read().strip()
  6. ret = msgpack.unpackb(packed, encoding='utf-8')
  7. print ret




レスポンスデータの最後に改行が入ります。
stripで取り除いておかないと、こんなエラーになりました。


Traceback (most recent call last):
File "sample.py", line 8, in <module>
    ret = msgpack.unpackb(packed, encoding='utf-8')
File "msgpack/_unpacker.pyx", line 143, in msgpack._unpacker.unpackb (msgpack/_unpacker.cpp:2143)
msgpack.exceptions.ExtraData: unpack(b) received extra data.




実行してみると、ちゃんと復元できています。


$ python sample.py
[True, {u'foo': u'bar'}]








MariaDBからデータ取得



lua nginx moduleからMariaDB(MySQL)に接続する(lua-sql-mysql)
こちらのサンプルを流用し、jsonではなくmessagepack形式のデータに変更してみます。

lua側のプログラム


  1. local mp = require 'MessagePack'
  2. -- bodyの解析
  3. ngx.req.read_body()
  4. -- body_dataを取得してみる
  5. local req_body = ngx.req.get_body_data()
  6. -- もし取得できていなかったら、データはファイルに行っている
  7. if not req_body then
  8.     -- テンポラリのファイル名を取得。内容を全部読み込む
  9.     local req_body_file_name = ngx.req.get_body_file()
  10.     if req_body_file_name then
  11.         local file = io.open(req_body_file_name, 'rb')
  12.         req_body = file:read('*a')
  13.         file:close()
  14.     end
  15. end
  16. if not req_body then
  17.     ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
  18. end
  19. -- postされた値を解析
  20. -- unpackでバイナリからオブジェクトに変換
  21. local post = mp.unpack(req_body)
  22. local driver = require 'luasql.mysql'
  23. env = assert (driver.mysql())
  24. con = assert (env:connect('sample', 'root', 'P@ssw0rd', 'localhost', 3306))
  25. -- 接続文字コードを変更
  26. assert (con:execute('SET NAMES utf8mb4'))
  27. -- 結果を取得
  28. result = {}
  29. cur = assert (con:execute(post.query))
  30. row = cur:fetch ({}, "a")
  31. while row do
  32. local copy_row = {}
  33. for field in pairs(row) do
  34. copy_row[field] = row[field]
  35. end
  36. table.insert(result, copy_row)
  37. row = cur:fetch (row, "a")
  38. end
  39. -- close everything
  40. cur:close() -- already closed because all the result set was consumed
  41. con:close()
  42. env:close()
  43. -- 結果セットをpackでバイナリに変換
  44. mp_raw = mp.pack(result)
  45. ngx.say(mp_raw)




クライアントとなるPython側のプログラム


  1. # -*- coding:utf-8 -*-
  2. import urllib2
  3. import msgpack
  4. data = msgpack.packb({u'query':u'select * from t where id = 2'})
  5. f = urllib2.urlopen('http://192.168.1.104/', data)
  6. mp_raw = f.read().strip()
  7. mp_data = msgpack.unpackb(mp_raw, encoding='utf-8')
  8. for row in mp_data:
  9.     print row['id'], row['value']




思いの外あっさり動きました。


$ python sample.py
2 日本語テスト2




テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/04/09(日) 21:29:29|
  2. Lua
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

lua nginx moduleからMariaDB(MySQL)に接続する(lua-sql-mysql)

Debian 8にインストールしたlua nginx moduleでいろいろ試しています。
apt-getでDebian 8 + lua nginx moduleの環境構築(nginx-extras)
lua nginx moduleでjson形式のレスポンスを返す(cjson)

MariaDB(MySQL)への接続を試してみます。


lua-sql-mysql



luaからMariaDBに接続する方法を調べてみると、lua-sql-mysqlを使用するのが良さそうでした。
https://keplerproject.github.io/luasql/

apt-getでインストールします。


# apt-get install lua-sql-mysql




同じサーバーにMariaDBをインストール。
「sample」データベース、「t」テーブルを作成しておきました。


  1. create table t (
  2. id int not null,
  3. value varchar(100) not null
  4. );






サンプル



「t」テーブルにデータを登録。
結果をjson形式で表示してみます。


  1. local driver = require 'luasql.mysql'
  2. env = assert (driver.mysql())
  3. con = assert (env:connect('sample', 'root', 'P@ssw0rd', 'localhost', 3306))
  4. -- 接続文字コードを変更
  5. assert (con:execute('SET NAMES utf8mb4'))
  6. -- 一旦テーブルの内容を削除
  7. assert (con:execute('DELETE FROM t'))
  8. -- 登録するデータ
  9. list = {
  10. { id=1, value='日本語テスト1', },
  11. { id=2, value='日本語テスト2', },
  12. }
  13. for i, row in pairs (list) do
  14. res = assert (con:execute(string.format([[
  15.     INSERT INTO t
  16.     VALUES (%s, '%s')]], row.id, con:escape(row.value))
  17. ))
  18. end
  19. -- 結果を取得
  20. result = {}
  21. cur = assert (con:execute("SELECT id, value from t"))
  22. row = cur:fetch ({}, "a")
  23. while row do
  24. local copy_row = {}
  25. for field in pairs(row) do
  26. copy_row[field] = row[field]
  27. end
  28. table.insert(result, copy_row)
  29. row = cur:fetch (row, "a")
  30. end
  31. -- close everything
  32. cur:close() -- already closed because all the result set was consumed
  33. con:close()
  34. env:close()
  35. local cjson = require "cjson"
  36. json_text = cjson.encode(result)
  37. ngx.say(json_text)






コネクション作成時の「env:connect」の引数は
データベース名,ID,パスワード,ホスト,ポート
となっており文字コードの指定はありません。

「SET NAMES utf8mb4」を実行して変更してやればうまく日本語が登録できました。

ブラウザで結果を表示してみます。

740_01.png




もう少し汎用的に



postで実行するsql文を受け取るように変更してみます。


  1. local cjson = require "cjson"
  2. -- bodyの解析
  3. ngx.req.read_body()
  4. -- body_dataを取得してみる
  5. local req_body = ngx.req.get_body_data()
  6. -- もし取得できていなかったら、データはファイルに行っている
  7. if not req_body then
  8.     -- テンポラリのファイル名を取得。内容を全部読み込む
  9.     local req_body_file_name = ngx.req.get_body_file()
  10.     if req_body_file_name then
  11.         local file = io.open(req_body_file_name, 'rb')
  12.         req_body = file:read('*a')
  13.         file:close()
  14.     end
  15. end
  16. if not req_body then
  17.     ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
  18. end
  19. -- postされた値を解析
  20. local post = cjson.decode(req_body)
  21. local driver = require 'luasql.mysql'
  22. env = assert (driver.mysql())
  23. con = assert (env:connect('sample', 'root', 'P@ssw0rd', 'localhost', 3306))
  24. -- 接続文字コードを変更
  25. assert (con:execute('SET NAMES utf8mb4'))
  26. -- 結果を取得
  27. result = {}
  28. cur = assert (con:execute(post.query))
  29. row = cur:fetch ({}, "a")
  30. while row do
  31. local copy_row = {}
  32. for field in pairs(row) do
  33. copy_row[field] = row[field]
  34. end
  35. table.insert(result, copy_row)
  36. row = cur:fetch (row, "a")
  37. end
  38. -- close everything
  39. cur:close() -- already closed because all the result set was consumed
  40. con:close()
  41. env:close()
  42. json_text = cjson.encode(result)
  43. ngx.say(json_text)




結果を要求するクライアントはPythonで作成してみました。


  1. # -*- coding:utf-8 -*-
  2. import urllib2
  3. import json
  4. data = json.dumps({u'query':u'select * from t where id = 2'})
  5. f = urllib2.urlopen('http://192.168.1.104/', data)
  6. json_text = f.read()
  7. json_data = json.loads(json_text)
  8. for row in json_data:
  9.     print row['id'], row['value']




狙い通りの実行結果です。


$ python sample.py
2 日本語テスト2





【参考URL】

LuaスクリプトからMySQLを利用するサンプル
https://keplerproject.github.io/luasql/examples.html
Luaのお勉強 テーブルの操作

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/04/09(日) 18:49:25|
  2. Lua
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

lua nginx moduleでjson形式のレスポンスを返す(cjson)

Debian 8でlua nginx moduleが動く環境を用意し、デバッグ方法を調べました。
apt-getでDebian 8 + lua nginx moduleの環境構築(nginx-extras)

簡単な文字列をngx.sayで返却しましたが、json形式の文字列を返してみます。



cjson



luaでjsonを扱うにはcjsonが便利そうです。
lua-cjson-manual

aptでインストールできるか調べたところ、


# apt-cache search cjson
lua-cjson - JSON parser/encoder for Lua
lua-cjson-dev - JSON parser/encoder for Lua, development files
python-cjson - Very fast JSON encoder/decoder for Python
python-cjson-dbg - Very fast JSON encoder/decoder for Python (debug extension)




lua-cjsonでインストールできそうです。


# apt-get install lua-cjson







サンプル



こちらで作成した環境を使います。
apt-getでDebian 8 + lua nginx moduleの環境構築(nginx-extras)

nginxの設定ファイル(/etc/nginx/sites-available/default)の抜粋。


    charset UTF-8;
    charset_types application/json;

    location / {
        lua_code_cache off;
        default_type 'application/json';
        content_by_lua_file /var/dev/lua/sample.lua;
    }




/var/dev/lua/sample.luaにプログラムを記載します。


  1. local cjson = require "cjson"
  2. value = { true, { foo = "bar" } }
  3. json_text = cjson.encode(value)
  4. ngx.say(json_text)




ブラウザで確認すると、ちゃんとjson形式の文字列になっているようです。

739_01.png


簡単なPythonのプログラムでも読み込みを試してみます。


  1. # -*- coding:utf-8 -*-
  2. import urllib2
  3. import json
  4. f = urllib2.urlopen('http://192.168.1.104/')
  5. json_text = f.read()
  6. print json_text
  7. print '-' * 10
  8. print json.loads(json_text)




ちゃんと復元できました。


$ python sample.py
[true,{"foo":"bar"}]

----------
[True, {u'foo': u'bar'}]






もう少し複雑な例



postでjson形式のデータを受け取り、内容に応じで値を返却してみます。

lua側のサンプル


  1. local cjson = require "cjson"
  2. -- bodyの解析
  3. ngx.req.read_body()
  4. -- body_dataを取得してみる
  5. local req_body = ngx.req.get_body_data()
  6. -- もし取得できていなかったら、データはファイルに行っている
  7. if not req_body then
  8.     -- テンポラリのファイル名を取得。内容を全部読み込む
  9.     local req_body_file_name = ngx.req.get_body_file()
  10.     if req_body_file_name then
  11.         local file = io.open(req_body_file_name, 'rb')
  12.         req_body = file:read('*a')
  13.         file:close()
  14.     end
  15. end
  16. if not req_body then
  17.     ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
  18. end
  19. -- postされた値を解析
  20. local post = cjson.decode(req_body)
  21. data = { status = 'ok', value = '取得したvalue:' .. post['value'] }
  22. json_text = cjson.encode(data)
  23. ngx.say(json_text)





リクエストの内容解析は過去の記事が役に立ちました。
nginx 1.6.2 + lua-nginx-moduleで簡易ファイルアップローダー


リクエストを送信するPython側のサンプル


  1. # -*- coding:utf-8 -*-
  2. import urllib2
  3. import json
  4. data = json.dumps({u'value':u'日本語'})
  5. f = urllib2.urlopen('http://192.168.1.104/', data)
  6. json_text = f.read()
  7. json_data = json.loads(json_text)
  8. print json_data['value']




実行結果


$ python sample.py
取得したvalue:日本語




日本語も問題なく処理できていますね。


【参考URL】

https://www.kyne.com.au/~mark/software/lua-cjson-manual.html
nginxで静的jsonファイル配信時に日本語が文字化けしないようにする

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/04/09(日) 17:15:37|
  2. Lua
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

apt-getでDebian 8 + lua nginx moduleの環境構築(nginx-extras)

nginxにluaを組み込むlua-nginx-module。
以前はソースからビルドしたのですが、
Debian 7 + nginx 1.6.2 + lua-nginx-moduleの環境構築
nginx-extrasをインストールすれば使用できるようです。
https://wiki.debian.org/Nginx

Debian 8にインストールして触ってみます。


nginx-extras



apt-getでインストール。


# apt-get install nginx-extras



nginxに加え、libluajit-5.1もインスールされました。


動作確認用に、nginxの設定ファイルへluaプログラムを記載してみます。


/etc/nginx/sites-available/default




location部分を変更。


    location / {
        default_type 'text/plain';
        content_by_lua "ngx.say('Hello,lua!')";
    }




default_type 'text/plain';がミソ。
この指定がないとファイルのダウンロードになります。

設定ファイル再読み込み。


# service nginx reload




ブラウザでhttp://[サーバーIP]を表示するとちゃんとメッセージが表示されました。

738_01.png


設定ファイルを変更した場合、service nginx reloadを実行しないと反映されません。


こんな感じで、表示するメッセージを変更した場合は、reloadしてやります。


    location / {
        default_type 'text/plain';
        content_by_lua "ngx.say('Hello,symfo!')";
    }



738_02.png





ファイルへ処理を記載



luaプログラムをファイルに記載する場合は、nginxの設定ファイルに


access_by_lua_file [ファイルのパス];



と記載します。

過去の記事が参考になりました。
nginx 1.6.2 + lua-nginx-moduleで簡易ファイルアップローダー
nginx 1.6.2 + lua-nginx-moduleでapache2 mod_access_tokenを実装


最初の例をluaファイルに記載してみます。

・/var/dev/lua/sample.lua


  1. ngx.say('Hello,lua!')




nginxの設定ファイルを変更します。


    location / {
        default_type 'text/plain';
        content_by_lua_file /var/dev/lua/sample.lua;
    }




設定ファイル再読み込み。


# service nginx reload




これで最初と同様の内容が表示されます。




デバック



ファイルを変更するたびに設定ファイルの再読み込みは面倒と思い調べてみると、
lua_code_cache


lua_code_cacheをoffにすると、毎回luaファイルを処理してくれるようです。
※もちろん、可動環境ではonにしておく必要あり。


nginxの設定ファイルに設定を追記します。


    location / {
        lua_code_cache off;
        default_type 'text/plain';
        content_by_lua_file /var/dev/lua/sample.lua;
    }




設定を反映


# service nginx reload




これでluaファイルの内容を変更後、ブラウザをリロードするとすぐに反映されるようになりました。



ログの出力は、こちらが参考になりました。
How to debug lua code inside nginx config?


作成した/var/dev/lua/sample.luaを修正。


  1. ngx.say('Hello,symfo!')
  2. ngx.log(ngx.STDERR, 'your message here')




ブラウザをリロードすると、nginxのエラーログ(/var/log/nginx/error.log)にメッセージが出力されます。


# tail -f /var/log/nginx/error.log
2017/04/09 15:14:10 [alert] 1290#0: aborting
2017/04/09 15:14:10 [info] 1301#0: Using 32768KiB of shared memory for push module in /etc/nginx/nginx.conf:63
2017/04/09 15:15:29 [notice] 1315#0: signal process started
2017/04/09 15:21:22 [notice] 1331#0: signal process started
2017/04/09 15:34:56 [notice] 1346#0: signal process started
2017/04/09 15:35:32 [notice] 1358#0: signal process started
2017/04/09 15:38:37 [alert] 1369#0: lua_code_cache is off; this will hurt performance in /etc/nginx/sites-enabled/default:38
2017/04/09 15:38:37 [notice] 1369#0: signal process started
2017/04/09 15:38:37 [alert] 1305#0: lua_code_cache is off; this will hurt performance in /etc/nginx/sites-enabled/default:38
2017/04/09 15:40:28 [] 1371#0: *15 [lua] sample.lua:2: your message here, client: 192.168.1.4, server: _, request: "GET / HTTP/1.1", host: "192.168.1.104"



テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/04/09(日) 15:48:16|
  2. Lua
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
次のページ