你的位置:首页 > 软件开发 > Java > Nodejs学习笔记(十六)

Nodejs学习笔记(十六)

发布时间:2017-11-24 15:00:19
目录前言&介绍安装Pomelo创建项目并启动创建项目项目结构说明启动测试连接聊天服务器新建gate和chat服务器配置master.json配置servers.json配置adminServer.json解决服务器分配问题实现gate.gateHandler.queryE ...

目录

  • 前言&介绍
  • 安装Pomelo
  • 创建项目并启动
    • 创建项目
    • 项目结构说明
    • 启动
    • 测试连接
  • 聊天服务器
    • 新建gate和chat服务器
    • 配置master.json
    • 配置servers.json
    • 配置adminServer.json
    • 解决服务器分配问题
    • 实现gate.gateHandler.queryEntry
    • 实现chat服务器chatRemote.js
    • 实现chat服务器chatHandler.js
    • 实现connector中entryHandler.js
    • 运行
  • 编写web聊天客户端测试
  • 写在之后

前言&介绍

Pomelo:一个快速、可扩展、Node.js分布式游戏服务器框架

从三四年前接触Node.js开始就接触到了Pomelo,从Pomelo最初的版本到现在,总的来说网易出品还算不错,但是发展不算快;用它做过一些项目和小游戏表现还不错。

用它的主要好处:

1. 入门简单,有比较丰富的文档和示例(虽然现在看版本也比较老了,但是入门没什么问题)

2.分布式多进程且扩展简单(单进程多线程,每个服务器都是一个Node进程,通过配置文件就可以管理集群)

3.可以不去关注底层和网络相关逻辑,聚焦业务逻辑的处理,对于有Web服务器开发经验却没有游戏服务器开发经验来说还是比较友好的

4.提供了很多工具和客户端支持(像IOS、Android & JavaJavascript、C、Cocos2d-x、U3D等)

......  

  入门参考链接

  https://github.com/NetEase/pomelo/wiki/Home-in-Chinese

  其它链接:  

  https://github.com/NetEase/pomelo

  https://www.npmjs.com/package/pomelo

安装Pomelo

  安装要求  

Windows下安装要求环境

Python (2.5 < 版本 < 3)

VC++编译器

PS:  Windows新环境自已检查一下,我本机环境已经装好python2.7,Visaul Studio也安装了所以也有VC++编译器

  其它操作系统应该问题不大

官方安装介绍文档:https://github.com/NetEase/pomelo/wiki/%E5%AE%89%E8%A3%85pomelo

    全局安装Pomelo

npm install pomelo -g

  安装成功后如下图,可以看到现在最新版本为2.2.5

 Nodejs学习笔记(十六)

 说明:Pomelo光是安装可能出现各种失败

    1. 回头去检查一下,Python和VC++编辑器是否有问题

    2.如果以前全局安装过Pomelo,最好删除掉 “C:\Users\当前用户\AppData\Roaming\npm\node_modules”目录下Pomelo文件夹和“C:\Users\当前用户\AppData\Roaming\npm-cache”目录下Pomelo开头的文件夹

    3.如果并不报错,npm卡住不动,多数是网络原因,重复多安几次;或者打开FQ工具试试;也可以用淘宝镜像 cnpm 安装

创建项目并启动

 安装好pomelo之后,开始创建项目并安装依赖项

pomelo init 项目名

 执行创建项目命令后,出现如下图选择项(Please select underly connector, 1 for websocket(native socket), 2 for socket.io, 3 for wss, 4 for socket.io(wss), 5 for udp, 6 for mqtt: [1]

Nodejs学习笔记(十六)

  这是让你选择connector的协议,除了5 for udp,其它都是长连接,我们接下来选择 2 for socket.io

  在上图cmd中输入2,并回车,选择socket.io继续安装

  这里connector协议可以通过app.js配置进行修改// app configuration

app.configure('production|development', 'connector', function(){ app.set('connectorConfig', {  connector : pomelo.connectors.sioconnector,
    ...
});});

  成功后,转到项目根目录,执行安装项目执行 npm-install.bat 依赖项 (其它平台执行npm-install.sh)

cd 项目目录npm-install.bat

 项目创建完成后,目录如下图

Nodejs学习笔记(十六)

  项目结构说明

  game-server :  游戏服务器,所有游戏服务器功能和逻辑都在此目录下

    game-server/app.js:入口文件

    game-server/app: 存放游戏逻辑和功能相关代码都这个子目录下,servers目录下可以新建多个目录来创建不同类型的服务器,在pomelo中,使用路径来区分服务器类型

    game-server/config:存放游戏服务器配置文件目录,像日志、服务器、数据库等几乎所有配置文件都可以存放到此目录下

    game-server/logs:日志目录,存放游戏服务器所有日志文件

  web-server:  web服务器(如果你是个H5游戏,这里就是Web客户端,如果是IOS、Andriod客户端,这目录就没什么用)

  shared:公共代码存放处,这里要以放一些共用代码

 所有依赖项安装成功后,开始启动项目

   启动game-server

cd game-serverpomelo start

    启动命令执行成功后,出现如下图错误提示

Nodejs学习笔记(十六)

[2017-11-23 11:54:42.226] [ERROR] console - Option path is not valid. Please refer to the README.[2017-11-23 11:54:42.226] [ERROR] console - Option close timeout is not valid. Please refer to the README.[2017-11-23 11:54:42.226] [ERROR] console - Option heartbeats is not valid. Please refer to the README.[2017-11-23 11:54:42.226] [ERROR] console - Option log level is not valid. Please refer to the README.

  问题原因和解决方式

  原因:新版的socket.io用法不正确的导致的,官方早已修复,就是没有publish到npm包中

  修复方式:把node_modules目录下的pomelo中sioconnector.js(../game-server/node_modules/pomelo/lib/connectors/sioconnector.js

                   替换为 https://github.com/NetEase/pomelo/blob/master/lib/connectors/sioconnector.js

 替换后再启动game-server,就没有这些错误提示了^_^!

 测试连接

  1.启动web-server

cd web-servernode app

 启动后如下图

Nodejs学习笔记(十六)

  会发些有一些提示,这是express写法问题,可以打开web-server根目录下app.js,按如下修改

//var app = express.createServer(); 注释掉这一行代码,替换为下面这一行代码var app = express();

 再启动时无express用法提示^_^!

 2.打 src='/images/loading.gif' data-original="http://images.cnblogs.com/cnblogs_com/zhongweiv/1119680/o_6.png" width="1122" height="721" />

 如上图,点击“Test Game Server”按钮,提示“game server is ok.”,则此项目game-server可用^_^!

聊天服务器

 上面大体了解了pomelo,要入门还是以一个聊天服务器为入门示例最好,其它逻辑相对简单,入门学习不会因其它游戏逻辑影响。

 官方有个非常好的示例:https://github.com/NetEase/chatofpomelo  官方也有很多说明

 网上也有很多文章分析讲解这项目,我就不完全解释些项目了,接下来我就在上面新建的好的“PomeloDemo”的基础上改成一个聊天服务器

 1.新建gate和chat服务器

  在app/servers目录下新建gate和chat服务器,新建好后目录如下

 Nodejs学习笔记(十六)

 gate服务器:

 在一般情况下用户量一台机器就可以支撑,但用户量多了就得扩充服务器,gate服务器的作用就相当于前端负载均衡服务器;

 客户端向gate服务器发出请求,gate服务器会给客户端分配一个connector服务器;

 分配策略是根据客户端的某一个key做hash得到connector的id,这样就可以实现各个connector服务器的负载均衡。这个一会儿会实现

 connector服务器: 

 接受客户端请求,并将其路由到chat服务器,以及维护客户端的链接;

 同时,接收客户端对后端服务器的请求,按照用户配置的路由策略,将请求路由给具体的后端服务器。当后端服务器处理完请求或者需要给客户端推送消息的时候,connector服务器同样会扮演一个中间角色,完成对客户端的消息发送;

 connector服务器会同时拥有clientPort和port,其中clientPort用来监听客户端的连接,port端口用来给后端提供服务;

 chat服务器:

 handler和remote决定了服务器的行为;

 handler接收用户发送过来的send请求,remote由connector RPC发起远程调用时调用;

 在remote里由于涉及到用户的加入和退出,所以会有对channel的操作。

 

 其实也可以提前了解一些Pomelo中的术语,不分别解释,可以提前看看:https://github.com/NetEase/pomelo/wiki/%E6%9C%AF%E8%AF%AD%E8%A7%A3%E9%87%8A

 

 2.配置master.json

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
{ "development": { "id": "master-server-1", "host": "127.0.0.1", "port": 15005 }, "production": { "id": "master-server-1", "host": "127.0.0.1", "port": 15005 }}
master.json

 

  3.配置servers.json

  打开config目录下servers.json文件,配置好各种 type 的服务器,配置如下

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
{ "development":{  "connector":[    {"id":"connector-server-1", "host":"127.0.0.1", "port":14050, "clientPort": 13050, "frontend": true},    {"id":"connector-server-2", "host":"127.0.0.1", "port":14051, "clientPort": 13051, "frontend": true},    {"id":"connector-server-3", "host":"127.0.0.1", "port":14052, "clientPort": 13052, "frontend": true}   ],  "chat":[    {"id":"chat-server-1", "host":"127.0.0.1", "port":16050},    {"id":"chat-server-2", "host":"127.0.0.1", "port":16051},    {"id":"chat-server-3", "host":"127.0.0.1", "port":16052}  ],  "gate":[   {"id": "gate-server-1", "host": "127.0.0.1", "clientPort": 15014, "frontend": true}  ] }, "production":{   "connector":[    {"id":"connector-server-1", "host":"127.0.0.1", "port":14050, "clientPort": 13050, "frontend": true},    {"id":"connector-server-2", "host":"127.0.0.1", "port":14051, "clientPort": 13051, "frontend": true},    {"id":"connector-server-3", "host":"127.0.0.1", "port":14052, "clientPort": 13052, "frontend": true}   ],  "chat":[    {"id":"chat-server-1", "host":"127.0.0.1", "port":16050},    {"id":"chat-server-2", "host":"127.0.0.1", "port":16051},    {"id":"chat-server-3", "host":"127.0.0.1", "port":16052}  ],  "gate":[   {"id": "gate-server-1", "host": "127.0.0.1", "clientPort": 15014, "frontend": true}  ] }}
servers.json

  解释一下配置中的各字段:

  id:   字符串类型的应用服务器ID

  host:应用服务器的IP或者域名

  port:RPC请求监听的端口

  clientPort: 前端服务器的客户端请求的监听端口

  frontend:bool类型,是否是前端服务器,默认: false

  可选参数:

  max-connections:前端服务器最大客户连接数

  args: node/v8配置,如配置为"args": "--debug=5858 "这样就可以启用项目调试(没用过,临时问了一下谷歌,看别人是这么解释的^_^!)

 

 4.配置adminServer.json

 打开config目录下adminServer.json文件,配置好各种 type 的服务器,配置如下

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
[{ "type": "connector", "token": "agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn"}, { "type": "chat", "token": "agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn"},{ "type": "gate", "token": "agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn"}]
adminServer.json

 它有什么作用,可以看一下以下2个链接

  “routeUtil.js”文件,处理此服务器分配逻辑

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
var crc = require('crc');module.exports.dispatch = function(uid, connectors) { var index = Math.abs(crc.crc32(uid)) % connectors.length; return connectors[index];};
dispatcher.jsNodejs学习笔记(十六)Nodejs学习笔记(十六)
var exp = module.exports;var dispatcher = require('./dispatcher');exp.chat = function(session, msg, app, cb) { var chatServers = app.getServersByType('chat'); if(!chatServers || chatServers.length === 0) {  cb(new Error('can not find chat servers.'));  return; } var res = dispatcher.dispatch(session.get('rid'), chatServers); cb(null, res.id);};
routeUtil.js

  准备好这些文件后,在game-server服务器入口文件app.js中添加配配置

var pomelo = require('pomelo');var routeUtil = require('./app/util/routeUtil');/** * Init app for client. */var app = pomelo.createApp();app.set('name', 'PomeloDemo');// app configuration// app.configure('production|development', 'connector', function(){app.configure('production|development', function(){ // route configures app.route('chat', routeUtil.chat); app.set('connectorConfig', {  connector : pomelo.connectors.sioconnector,  // 'websocket', 'polling-xhr', 'polling-jsonp', 'polling'  transports : ['websocket', 'polling'],  heartbeats : true,  closeTimeout : 60 * 1000,  heartbeatTimeout : 60 * 1000,  heartbeatInterval : 25 * 1000 }); // filter configures app.filter(pomelo.timeout());});// start appapp.start();process.on('uncaughtException', function (err) { console.error(' Caught exception: ' + err.stack);});
   app.filter(pomelo.timeout());    过滤器,pomelo内置了一些过滤器,可以自行去了解一下,也可以根据自已的需求去自定义!  

 注意:

   app.configure('production|development', 'connector', function(){   

   修改为

   app.configure('production|development',  function(){

   这个如果不修改,在启动调用时会遇到 engine.io 中报错  TypeError: Cannot read property  'indexOf' of undefined  at Server.verify !

 

 6.实现 gate.gateHandler.queryEntry

  作用:用户连接gate服务器,返回分配的connector

  在gate目录下handler下新建gateHandler.js,代码如下

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
var dispatcher = require('../../../util/dispatcher');module.exports = function(app) { return new Handler(app);};var Handler = function(app) { this.app = app;};var handler = Handler.prototype;/** * Gate handler that dispatch user to connectors. * * @param {Object} msg message from client * @param {Object} session * @param {Function} next next stemp callback * */handler.queryEntry = function(msg, session, next) { var uid = msg.uid; if(!uid) {  next(null, {   code: 500  });  return; } // get all connectors var connectors = this.app.getServersByType('connector'); if(!connectors || connectors.length === 0) {  next(null, {   code: 500  });  return; } // select connector var res = dispatcher.dispatch(uid, connectors); next(null, {  code: 200,  host: res.host,  port: res.clientPort });};
gateHandler.js

 

 7.实现chat服务器chatRemote.js 

 chat服务器会接受connector的远程调用,完成channel维护中的用户的加入以及离开

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
module.exports = function(app) { return new ChatRemote(app);};var ChatRemote = function(app) { this.app = app; this.channelService = app.get('channelService');};/** * Add user into chat channel. * * @param {String} uid unique id for user * @param {String} sid server id * @param {String} name channel name * @param {boolean} flag channel parameter * */ChatRemote.prototype.add = function(uid, sid, name, flag, cb) { var channel = this.channelService.getChannel(name, flag); var username = uid.split('*')[0]; var param = {  route: 'onAdd',  user: username }; channel.pushMessage(param); if( !! channel) {  channel.add(uid, sid); } cb(this.get(name, flag));};/** * Get user from chat channel. * * @param {Object} opts parameters for request * @param {String} name channel name * @param {boolean} flag channel parameter * @return {Array} users uids in channel * */ChatRemote.prototype.get = function(name, flag) { var users = []; var channel = this.channelService.getChannel(name, flag); if( !! channel) {  users = channel.getMembers(); } for(var i = 0; i < users.length; i++) {  users[i] = users[i].split('*')[0]; } return users;};/** * Kick user out chat channel. * * @param {String} uid unique id for user * @param {String} sid server id * @param {String} name channel name * */ChatRemote.prototype.kick = function(uid, sid, name, cb) { var channel = this.channelService.getChannel(name, false); // leave channel if( !! channel) {  channel.leave(uid, sid); } var username = uid.split('*')[0]; var param = {  route: 'onLeave',  user: username }; channel.pushMessage(param); cb();};
chatRemote.js

 可以看到上面代码中的add和kick分别对应着加入和离开channel

 

 8.实现chat服务器chatHandler.js

 chat服务器执行聊天逻辑,维护channel信息,一个房间就是一个channel,一个channel里有多个用户,当有用户发起聊天的时候,就会将其内容广播到整个channel。

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
var chatRemote = require('../remote/chatRemote');module.exports = function(app) { return new Handler(app);};var Handler = function(app) { this.app = app;};var handler = Handler.prototype;/** * Send messages to users * * @param {Object} msg message from client * @param {Object} session * @param {Function} next next stemp callback * */handler.send = function(msg, session, next) { var rid = session.get('rid'); var username = session.uid.split('*')[0]; var channelService = this.app.get('channelService'); var param = {  route: 'onChat',  msg: msg.content,  from: username,  target: msg.target }; channel = channelService.getChannel(rid, false); //the target is all users if(msg.target == '*') {  channel.pushMessage(param); } //the target is specific user else {  var tuid = msg.target + '*' + rid;  var tsid = channel.getMember(tuid)['sid'];  channelService.pushMessageByUids(param, [{   uid: tuid,   sid: tsid  }]); } next(null, {  route: msg.route });};
chatHandler.js

 这里面是发送消息(给房间内所有人和指定用户)

 

 9.实现connector中entryHandler.js

  主要完成接受客户端的请求,维护与客户端的连接,路由客户端的请求到chat服务器;

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
module.exports = function(app) { return new Handler(app);};var Handler = function(app) {  this.app = app;};var handler = Handler.prototype;/** * New client entry chat server. * * @param {Object} msg  request message * @param {Object} session current session object * @param {Function} next next stemp callback * @return {Void} */handler.enter = function(msg, session, next) { var self = this; var rid = msg.rid; var uid = msg.username + '*' + rid var sessionService = self.app.get('sessionService'); //duplicate log in if( !! sessionService.getByUid(uid)) {  next(null, {   code: 500,   error: true     });  return; } session.bind(uid); session.set('rid', rid); session.push('rid', function(err) {  if(err) {   console.error('set rid for session service failed! error is : %j', err.stack);  } }); session.on('closed', onUserLeave.bind(null, self.app)); //put user into channel self.app.rpc.chat.chatRemote.add(session, uid, self.app.get('serverId'), rid, true, function(users){  next(null, {   users:users  }); });};/** * User log out handler * * @param {Object} app current application * @param {Object} session current session object * */var onUserLeave = function(app, session) { if(!session || !session.uid) {  return; } app.rpc.chat.chatRemote.kick(session, session.uid, app.get('serverId'), session.get('rid'), null);};
entryHandler.js

  这里完成的主要就是RPC远程调用chat服务器chatRemote中的实现

 

10.运行

  到此这个聊天服务器实现就完成, 打开命令行工具,执行没有错误信息,基本就成功了!

cd game-server目录pomelo start

 

编写web聊天客户端测试

  我就在web-server目录中写了个测试客户端

  把结构改了一下,换成了ejs模版,代码如下

  routes中index.js文件代码

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
var express = require('express');var router = express.Router();router.get('/', function (req, res, next) { res.render('index', { title: 'Nodejs学习笔记(十六)--- Pomelo介绍&入门' });});module.exports = router;
index.js

 views中index.ejs文件代码

<html><head><title><%= title %></title></head><body> <div id="tipMsg" ></div> <div id="pnlLogin">  <h1>1.登录(连接Gate服务器)</h1> 用户名:<input id="txtUserName" type="text" maxlength="20" ></br> 房间号:<input id="txtRoomId" type="text" maxlength="8" > <input id="btnLogin" type="button" value="点击登录" /> <br/> </div>  <div id="pnlChat" > <h1>2.聊天室</h1>  用户名:<span id="spUserName" ></span> 房间号:<span id="spRoomId" ></span>  <div id="txtMessage" ></div> <br/> 发送给:<select id="selUserList" >    <option value="*">所有人</option>   </select>   <br/>   <br/>   <textarea id="txtSendMessage" type="text" ></textarea>   <input id="btnSend" type="button" value="发送" /> </div></body></html><script src='/images/loading.gif' data-original="js/socket.io.js"></script><script src='/images/loading.gif' data-original="js/pomeloclient.js"></script><script src='/images/loading.gif' data-original="js/jquery-1.11.2.min.js"></script><script type="text/javascript">$(function(){ var rid = ''; var uname = ''; //监听"onAdd", 当有新用户加入时触发 pomelo.on('onAdd', function(data) {  var user = data.user;  $('#txtMessage').append('<span >[上线提醒]:欢迎 ' + user + ' 加入聊天室<span><br/>');  //添加到用户列表  $('#selUserList').append('<option value="' + user + '">' + user + '</option>'); }); //监听"onLeave", 当有用户离开聊天室时触发 pomelo.on('onLeave', function(data) {  var user = data.user;  $('#txtMessage').append('<span >[离线提醒]: ' + user + ' 离开聊天室<span><br/>');   //从用户列表移除  $('#selUserList option[value="' + user + '"]').remove(); }); // 监听"onChat", 接收消息 pomelo.on('onChat', function(data) {  var from = data.from,   target = data.target,   msg = data.msg;         if(msg === null) return;  var name = (target == '*' ? '所有人' : target);  var time = getNowFormatDate();      $("#txtMessage").append('<span >[' + time +'][' + from + '] 对 [' + name + '] 说: ' + msg + '<span><br/>'); }); //当从聊天断开时 pomelo.on('disconnect', function(reason) {    $('#pnlLogin').show();  $('#pnlChat').hide();     }); //登录 $('#btnLogin').on('click', function(){  var userNameReg = /^[a-zA-Z0-9]+$/,   roomIdReg = /^[0-9]+$/;   uname = $.trim($('#txtUserName').val()),   rid = $.trim($('#txtRoomId').val());  if(uname.length == 0){   alert('请输入登录名');   return false;  }  if(!userNameReg.test(uname)) {   alert('登录名只能由字母或数字组成');   return false;  }  if(rid.length == 0){   alert('请输入房间号');   return false;  }  if(!roomIdReg.test(rid)) {   alert('房间号只能是数字');   return false;  }    queryEntry(uname, function(host, port){   $('#tipMsg').append('Gate 连接成功! host:' + host + ' port:' + port + '<br/>');      //连接聊天服务器   pomelo.init({    host: host,    port: port,    log: true   }, function() {    var route = "connector.entryHandler.enter";    pomelo.request(route, {     username: uname,     rid: rid    }, function(data) {     if(data.error) {      $('#tipMsg').append('Chat 连接失败!<br/>');      return;     }        $('#tipMsg').append('Chat 连接成功!<br/>');     $('#pnlLogin').hide();     $('#pnlChat').show();     $('#spUserName').text(uname);     $('#spRoomId').text(rid);     //加载当前聊天室 已在线用户列表     $.each(data.users, function(i, item){            if(item != uname){       $('#selUserList').append('<option value="' + item + '">' + item + '</option>');      }           });     });   });  }); }); //发送消息 $('#btnSend').on('click', function(){  var route = "chat.chatHandler.send",   target = $("#selUserList").val(),   msg = $.trim($("#txtSendMessage").val());     if(msg.length == 0){   alert('不能发送空消息!');   return;  }  pomelo.request(route, {   rid: rid,   content: msg,   from: uname,   target: target  }, function(data) {      $("#txtSendMessage").val('');   if(from == uname) {    var name = (target == '*' ? '所有人' : target);    var time = getNowFormatDate();        $("#txtMessage").append('<span >[' + time +'][' + from + '] 对 [' + name + '] 说: ' + msg + '<span><br/>');   }  });   });  })//连接Gate服务器function queryEntry(uid, callback) { var route = 'gate.gateHandler.queryEntry'; pomelo.init({  host: '127.0.0.1',  port: 15014,  log: true }, function() {   pomelo.request(route, {   uid: uid  }, function(data) {   pomelo.disconnect();   if(data.code === 500) {        alert('用户名在此房间中已存在,请重新输入新的用户名!');    return;   }   callback(data.host, data.port);  }); });};function getNowFormatDate() { var date = new Date(); var seperator1 = "-"; var seperator2 = ":"; var month = date.getMonth() + 1; var strDate = date.getDate(); if (month >= 1 && month <= 9) {  month = "0" + month; } if (strDate >= 0 && strDate <= 9) {  strDate = "0" + strDate; } var currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate   + " " + date.getHours() + seperator2 + date.getMinutes()   + seperator2 + date.getSeconds(); return currentdate;}</script>

   app.js代码如下:

Nodejs学习笔记(十六)Nodejs学习笔记(十六)
var express = require('express');var path = require('path');var logger = require('morgan');var cookieParser = require('cookie-parser');var bodyParser = require('body-parser');var app = express();var index = require('./routers/index.js');// views engine setupapp.set('views', path.join(__dirname, 'views'));app.set('view engine', 'ejs');app.use(logger('dev'));app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: false }));app.use(cookieParser());app.use(express.static(path.join(__dirname, 'public')));app.use('/', index);app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; res.render('404');});if (app.get('env') === 'development') { app.use(function(err, req, res, next) {  console.log(err);  res.status(err.status || 500);  res.render('500', {   message: err.message,   error: err  }); });}app.use(function(err, req, res, next) { console.log(err); res.status(err.status || 500); res.render('500', {  message: err.message,  error: {} });});app.listen(10111, function () { console.log("You can debug your app test with >);});module.exports = app;
app.js

 

 运行起来后,测试结果如下图:

Nodejs学习笔记(十六)

 

写在之后

   Pomelo学习入门不算复杂,写一篇感觉讲不全,写多篇感觉太散,大家将就着看,有些东西不认识的还是去看一下API文档  (也是低水准的官方API^_^!)

   或者问一下google啥的... 

   可以参考这两个例子来学习:

   https://github.com/NetEase/chatofpomelo

   https://github.com/NetEase/lordofpomelo

   入门建议从chatofpomelo开始

   看之前可以提前看看一些pomelo术语,有个大体了解,再边看代码边理解:https://github.com/NetEase/pomelo/wiki/%E6%9C%AF%E8%AF%AD%E8%A7%A3%E9%87%8A

 

   主要参考资料:

   https://github.com/NetEase/pomelo/wiki/Home-in-Chinese  (比较杂乱,可能官方大神都忙着搞赚钱的项目,将就着看,有很多东西对入门来说还是很有用的)

   

   如果有些问题解决不了,可以去社区问一下 (感觉现在活跃度也比较低^_^!)

 

海外公司注册、海外银行开户、跨境平台代入驻、VAT、EPR等知识和在线办理:https://www.xlkjsw.com

原标题:Nodejs学习笔记(十六)

关键词:JS

JS
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。