自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた

  • 15,450 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
15,450
On Slideshare
0
From Embeds
0
Number of Embeds
7

Actions

Shares
Downloads
11
Comments
0
Likes
7

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. 自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた
  • 2. MikeTokyo???しかもなんか見たことあるアイコンじゃね?
  • 3. これだ!!!!!!
  • 4. 僕と、〇〇でラジオやります!もうブース押さえてます!(10/20(土)22:00∼)
  • 5. ただ、ラジオやるなら、WEBサイトが必要ですよね!
  • 6. 僕はphperなので、apache+mod-phpでWEBサイト作(ry
  • 7. いや、ちょっと待て!今の時代にapache+mod-phpは古くね?
  • 8. サイトの規模も小さいし、勉強がてらnode.js+nginxで作ろう!
  • 9. What is node.js?Javasctiptでサーバーサイドプログラミングを行うことが出来る環境の総称です。特徴・V8 javascript(google chromeのjavascript実行環境)を利用しているため、動作が軽快・イベントドリブンなプログラミングスタイル・シングルスレッドのイベントループモデル(apacheのようにリクエスト毎にスレッドを立てるのではなく、シングルスレッドで処理をキューにためて実行する。このため、メモリの使用量がapacheなどのサーバーに比べて少ない)・ノンブロッキングI/O(i/oの完了を待たずに次の処理が実行される。ブラウザで動作するjavascriptのように、パラレルで処理が実行される。普通のイベントループモデルだと重い処理がブロッキングを行って次の処理が遅延するが、ノンブロッキングI/Oのおかげでnode.jsではブロッキングが発生しない。)・以上のことから、大量アクセスのあるリアルタイムWEBを始めとしたネットワークプログラミングが得意
  • 10. What is nginx?軽量かつ、WEBサーバー、リバースプロキシー、IMAP/POP3、LBとして使用可能な高性能WBサーバーのこと特徴・node.js同様、非同期のイベント駆動型のリクエスト処理を用いているため負荷に強い・apacheほど設定も難解ではないので、扱いやすい・Fast-CGIをデフォルト備えているので、phperである僕らはphp-FPMを容易に扱うことができる・とりあえずめちゃめちゃ流行っている。Response HeaderのServer項目がnginxというのをマジでよく見かける
  • 11. node.jsでWEBアプリケーションとなると.... cofeescript、jadeのほか、Redis、 MongoDBをすぐに扱えるnode.js  史上最強MVCフレームワークhttp://towerjs.org/ rubyのsinatraライクな軽量フレーム ワーク http://expressjs.com/
  • 12. ただ、node.jsでのプログラミングのイロハがまだ不確かなままFWを使うのも嫌なので、自分でFW作って学 びながらモノ作りしたい!
  • 13. 本題
  • 14. Architecter nginx(静的ファイル) port 80クライアント request response proxy 簡単な仕様 node.js(動的処理)・RonRライクなMVCパターンを採用 port3000・ORMなし・scafoldなし response・ Templateエンジンにejsを採用・jsUnitを採用(予定)
  • 15. Architecter続き①リクエスト ②リクエストハンドラ ③コントローラーのインスタンス生成 ④アクション実行 ⑤レスポンスデータの生成 (html、jpg、404等) ⑥レスポンス
  • 16. MVCFrameWorkに最低限必要なもの・RequestHandler・Configuration・Router・Model・View・Controller
  • 17. ディレクトリ構成miketokyo |-app |-config |-config.js |-router.js |-bootstrap.js |-controllers |-models |views |-layouts |-system |-server |-view.js |-router.js |-controller.js |-share.js |-response.js |-utility.js |-server.js |-package.json |-.gitignore
  • 18. リクエストハンドラの実装 server.js(紙面の都合上章や略しております。)var  http  =  require("http");var  url  =  require("url");(function  start()  {    function  onRequest(request,  response)  {                //アプリケーション初期化                var  router  =  require("./app/config/router.js");                var  pathname  =  url.parse(request.url).pathname;                var  bootstrap  =  require("./app/config/bootstrap");                bootstrap.init(request,  response);                var  env  =  require("./app/config/env/"  +  bootstrap.env);                var  config  =  require("./app/config/config");                var  share  =  require("./system/server/share");                share.config  =  config;                var  __CONTROLLER__  =  router.controller;                var  __ACTION__  =  router.action;                if(pathname  !=  "/"){                    __CONTROLLER__  =  pathname.split("/")[1];                    __ACTION__  =  (typeof  pathname.split("/")[2]  ==  "string")  ?  pathname.split("/")[2]  :  "index";                }                var  className  =  __CONTROLLER__.charAt(0)  +  __CONTROLLER__.substring(1)  +  "Controller";  //クラス名を動的に形成する                var  _controller  =  require("./app/controllers/"  +  className);                var  controllerInstance  =  new  _controller();                controllerInstance.request  =  request;                controllerInstance.response  =  response;                controllerInstance.headers  =  request.headers;                controllerInstance.headers.userAgent  =  require(user-­‐agent).parse(request.headers[user-­‐agent]).full;                controllerInstance.init();                var  assignVars  =  eval("controllerInstance."  +  __ACTION__  +  "Action()");                var  view  =  require("./system/server/view");                view.render(controllerInstance.layoutPath  ,  controllerInstance.renderPath  ,  assignVars,  response);    }    http.createServer(onRequest).listen(3000);})();
  • 19. 環境判別等を行うbootstrapを作成するapp/config/bootstrap.jsvar  bootstrap  =  {   env  :  "localhost"   ,init  :  function(req,  res){                    //ホストから環境を判別する var  this.env  =  (function(host){        var  hostSplits  =  host.split(".");        if(hostSplits[0].match(/dev|stg/)){ return  hostSplits[0]; }else{ return  "production"; })(req.headers.host); }   }}module.exports  =  bootstrap;
  • 20. 設定ファイルを作成するapp/config/config.jsvar  config  =  {   applicationName  :  "MikeTokyo"}module.exports  =  config;
  • 21. BaseとなるControllerクラスの作成system/controller.jsfunction  controller(){}controller.prototype  =  {   request  :  null,   response  :  null,   headers  :  null,   renderPath  :  null,   layoutPath  :  "base",        init  :  function(){},      //void  redirect   redirect  :  function(url){     this.response.writeHead(302,  {           Location:  url     });     this.response.end();     },      //void  render   render  :  function(path){     this.renderPath  =  path;   },      //void  layout   layout  :  function(path){     this.layoutPath  =  path;   }}module.exports  =  controller;
  • 22. Viewクラスの作成 system/view.jsvar  fs  =  require("fs");var  ejs  =  require("ejs");var  share  =  require("./share");var  view  =  {   templateVars  :  {}   ,viewExt            :  ".ejs"   ,layoutPath      :  null   ,templatePath  :  null        //htmlをクライアントに返す   render  :  function(layoutPath,  templatePath,  templateVars,  response){ var  templatePath    =  share.APP_PATH  +  "views/layout/"  +  templatePath  +  this.viewExt;     fs.readFile(templatePath,"utf8",  function(err,data){                        //renderで指定されたtemplateをhtmlに置換して取得する                          var  actionData  =  ejs.render(data,vars);                     fs.readFile((function(path){                                                  var  templatePath  =  share.APP_PATH  +  "views/";                                                    if(path  !==  undefined  &&  path  !==  null){                                                                  return  templatePath  +=  path  +  this.viewExt;                                                           }else{                                                              return  templatePath  +=  share.__ACTION__  +  this.viewExt;                                                        }                            })(layoutPath),"utf8",  function(err,data2){                            //layoutで指定されたtemplateに、actionDataを埋め込みHTMLとしてクライアントに返す                      var  finalOutput  =  ejs.render(data2,{content  :  actionData,                                                                                            applicationName  :  share.config.applicationName});                      response.writeHead(200,  {  Content-­‐Type:  text/html;  charset=utf-­‐8  });                      response.end(finalOutput);                  });            });   },}module.exports  =  view;
  • 23. routerクラスの作成system/server/router.jsvar  url  =  require("url");var  router  =  {    req:null  ,controller:  "app"  ,action  :  "index"  ,connect  :  function(pattern,  routeUrl){        var  patt  =  pattern.replace(/,  "/");        var  pathname  =  url.parse(this.req.url).pathname;        if(pathname.match(patt)){            this.controller  =  routeUrl.split("/")[0];            this.action  =  routeUrl.split("/")[1];        }    }}module.exports  =  router;
  • 24. Frame Workの基幹が出来たので、実際に使ってみるお!
  • 25. appControllerの作成app/controllers/appController.js//ライブラリインポートvar  share  =  require("../../system/server/share");var  utility  =  require("../../system/server/utility");function  appController(){}//継承var  appController  =    utility.extend(appController,  require("../../system/server/controller"));appController.prototype.init  =  function(){   this.layout("base");}appController.prototype.indexAction  =  function(){   return  {applicationName:"MikeTokyo"  };}appController.prototype.testAction  =  function(){        this.render("test");}module.exports  =  appController;
  • 26. 各種viewの作成app/views/layout/base.ejs<!doctype  html><html>   <head>   <meta  charset="UTF-­‐8">   <title><%=applicationName  %></title>   </head>   <body>     <%-­‐content  %>   </body></html>app/views/index.ejs<h1><%=applicationName  %>:Index</h1><img  src="/img/common/logo.jpg"><a  href="/app/test"  >testへ</a>
  • 27. routerの設定app/config/router.jsvar  router  =  require("../../system/server/router");router.connect("/",  "app/index");module.exports  =  router;
  • 28. nginxの設定/etc/nginxd/nginx.confserver { listen 80; server_name miketokyo.com; root /var/www/nginx-default; access_log /var/log/nginx/localhost.access.log; #指定した拡張子のファイルはnginxでさばく location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ { root /var/www/miketokyo/app/webroot/ expires 15d; } #プロキシの設定 location / { proxy_pass http://127.0.0.1:3000; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Nginx-Proxy true; proxy_redirect off; }}
  • 29. 実際にアクセスしてみるお!
  • 30. http://miketokyo.com/
  • 31. 無理やりですが、とても簡単にWEBアプリが作れてしましますね!!
  • 32. node.js開発時のティップス・クラスの名前は、「camelCase」のようなキャメルケースとなる・自分でhttpサーバーを作るということを意識する。html以外にも、jpgやcssなどもcontent-typeを指定してクライアントに返す必要がある。もちろん、404や500も。・シングルスレッドで動作するため、例えば、「this.propety++」として初期化しないで放置すると、次のリクエストでは、前のリクエストでインクリメントされた値をさらにインクリメントして処理されるため、phpやjavaのノリで「this.propety++」や「this.propety += hoge」を書くと大変!!・例外が発生するとnode.jsのプロセス自体が落ちてアボーんする(適切に全ての例外をcatchして500などを返すか、foreverというnode.jsをデーモン化するモジュールを導入することで対応可能)・複雑な処理を書くとコールバックの嵐となるため、Defferdとかを使ったほうがよさそう。・JQueryもつかえるよ!・CofeeScriptでも書けるよ!
  • 33. まとめ・node.jsはsocket.ioだけじゃなく、WEBアプリだって作れる! しかも簡単に!・Smartyやjspと同等レベルで扱えるtemplateエンジンがある!(その他hamlを扱えるjade等も存在する)・各クラスやライブラリをモジュール化することで、OOPプログラミングができる・同じくイベントループモデルのWEBサーバーであるnginxと相性がいい・今回は登場していませんが、mysqlやmongodbなどのDBドライバ、RedisやmemcacheなどのKVS向けドライバも用意されているので、phpやjavaと同等のWEB開発ができる・依存関係を最小限にクラス設計をするのに時間がかかりそう。。
  • 34. 今回紹介したmiketokyoフレームワークは、github上で開発されています笑みんなコミッターになってね♥https://github.com/noppoMan/mike_tokyo
  • 35. ご静聴ありがとうございました