【问题标题】:Hosting a nodejs server on dotcloud在 dotcloud 上托管 nodejs 服务器
【发布时间】:2013-02-01 03:10:31
【问题描述】:

我正在尝试在托管服务“dotcloud”上托管一个 nodejs 应用程序。 我的 nodejs 使用包“websocket”来处理通信。 IE。 npm install websocket

我的应用在笔记本电脑的本地主机上运行时运行良好。但是当我在 dotcloud 上部署应用程序时,它无法正常工作。

这是怎么回事:您将浏览器指向 dotcloud 上的 url: pirate-captainlonate.dotcloud.com

然后,express 使用 express.get('/'.......){} 处理 GET 请求 express 按照您的预期将 .html 页面提供给客户端。 .html 文件 反过来尝试与服务器建立 websocket 连接。我又能得到 这在我的本地机器上工作得很好。但是,没有建立连接。 具体来说,dotcloud 肯定是在为我提供 .html 文件,但 .html 文件没有与服务器建立 websocket 连接。但是 connection.onerror 也没有被调用。有点奇怪。

这里有一些代码可以帮助你理解我在做什么:

客户端:

this.connection = new WebSocket('ws://pirate-captainlonate.dotcloud.com:1337'); 

this.connection.onerror = function (error) {
        console.log("ERROR with the connection *sadface*");
    };

**** Note that I note the onerror function here to show that I do indeed have it set up, but it's not being called. It would seem that no error is being thrown.

服务器端:

var webSocketServer = require('websocket').server; // websocket
var server = require('http').createServer();
var expr = require("express"); // load the express module
var xpress = expr(); // xpress now holds the server object

// Helps Node serve the game.html page upon a get request
xpress.configure(function() {
    xpress.use(expr.static(__dirname + "/public"));
     xpress.set("view options", {layout: false});
});

// All requests to root serve the game.html page
xpress.get('/', function(req, res) {
    res.sendfile(__dirname + '/public/game.html');
});

// What ports to listen on
var webSocketsServerPort = 1337;
xpress.listen(8080);
server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});

// WebSocket Server
var wsServer = new webSocketServer({
    httpServer: server
});

这应该足以向你们展示它是如何工作的。现在你们可能会问,“>> dotcloud logs”显示的是什么?

[www.0] ==> /var/log/supervisor/app.log <==
[www.0] Sat Feb 16 2013 02:57:59 GMT+0000 (UTC) Server is listening on port 1337
[www.0] ==> /var/log/supervisor/supervisord.log <==
[www.0] 2013-02-16 02:57:57,946 WARN Included extra file "/home/dotcloud/current/supervisord.conf" during parsing
[www.0] 2013-02-16 02:57:58,033 INFO RPC interface 'supervisor' initialized
[www.0] 2013-02-16 02:57:58,033 WARN cElementTree not installed, using slower XML parser for XML-RPC
[www.0] 2013-02-16 02:57:58,033 CRIT Server 'unix_http_server' running without any HTTP authentication checking
[www.0] 2013-02-16 02:57:58,038 INFO daemonizing the supervisord process
[www.0] 2013-02-16 02:57:58,039 INFO supervisord started with pid 140
[www.0] 2013-02-16 02:57:59,048 INFO spawned: 'app' with pid 154
[www.0] 2013-02-16 02:58:00,290 INFO success: app entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
[db.0] ==> /var/log/mongodb/mongodb.log <==
[db.0] Sat Feb 16 01:45:02 [conn4] end connection 127.0.0.1:51326 (0 connections now open)

好的,我真的很想让这个工作。我一直在这。如果你们还有什么需要帮助我回答我的问题,请告诉我。

谢谢,

--内森

附录:这是服务器发送 html 文件的方式。

xpress.get('/', function(req, res) {
    res.sendfile(__dirname + '/public/game.html');
});

【问题讨论】:

  • 很好的问题,很多信息,很容易找到你的问题。基本上你需要第二个 http 端口。我在下面的回答中解释了如何做到这一点。

标签: javascript node.js websocket dotcloud


【解决方案1】:

看起来您正在尝试为您的服务使用 2 个 http 端口,而 dotCloud 仅支持 1 个开箱即用,因此您需要通过在您的服务中添加一个小 sn-p 让他们知道您想要另一个dotcloud.yml

这是一个示例 dotcloud.yml,它要求第二个名为 server

的 tcp 端口
app:
    type: nodejs
    ports:
       server: tcp
    config:
       node_version: v0.8.x

添加并推送后,您的服务器将获得可用于服务器的第二个 TCP 端口,您只需要通过从环境文件中获取值来找出该端口。

这是一个 sn-p,它可以从 ENV 获取您的端口,如果不存在,它将默认为 4242,因此您仍然可以在本地运行。

var webSocketsServerPort = process.env['PORT_SERVER'] || 4242;

如果您想知道我是如何获得 ENV 变量名称的,这很简单。它将是 PORT_,然后是来自 dotcloud.yml 的名称的大写字符串。由于我在上面使用了 server,它变成了 PORT_SERVER,如果我使用关于它的节点将是 PORT_NODE,所以放你想要的,但要确保这些值匹配。

客户:

要找出您需要连接到客户端上的哪个端口,您需要再次返回您的环境变量。这次您正在寻找一个类似于DOTCLOUD_APP_SERVER_PORT 的变量。 重要提示:您的变量名可能不同

我是如何得到那个环境变量名的?

变量名看起来像这样DOTCLOUD_{{app_name}}_{{port_name}}_PORT全部大写。将 {{variable}} 替换为以下信息。

{{app_name}} = 来自 dotcloud.yml 的应用名称,在上面的示例中为 app {{port_name}} = 端口名称,server 在上面的 dotcloud.yml 示例中。

要找到它,您可以从您的应用程序environment.json、environment.yml 文件、shell ENV 变量或登录到 dotCloud 仪表板,单击您的应用程序,然后单击环境选项卡以查看您的列表应用程序变量。

如果您进行了这三个更改,您的问题应该会消失。

如果您需要更多代码示例,请查看此 github 存储库,该存储库执行与您尝试执行的操作类似的操作。

https://github.com/3on/node-tcp-on-dotcloud

【讨论】:

  • 好的,但是如果我这样做,那么我的客户端会尝试在哪个端口上建立连接?我尝试了没有端口,4242、1337,然后我尝试制作一些 mumbo jumbo,结果令人惊讶。不管我在 WebSocket() 构造函数调用中放了什么,我每次都得到相同的结果:没有错误,没有建立连接..
  • @Captainlonate 我更新了答案,包括如何找出可以从客户端连接到的端口。
  • 好吧,Ken,状态更新:我试过你说的,但我不能在我的 client.js 文件中使用 process.env[]。无论括号'[]'中的内容是什么,都无法识别函数调用“process.env”。 Chrome 的控制台说: Uncaught ReferenceError: process is not defined 。为清楚起见,这就是我的 client.js 文件中的行所说的: var thePort = process.env['DOTCLOUD_APP_SERVER_PORT'];坚持我,肯,我非常希望这能奏效。
  • 附录:在我创建了上面的变量之后,我的意图是这样使用它:console.log('ws://pirate-captainlonate.dotcloud.com:' + thePort);跨度>
  • 是否有一些可能的方法可以将端口与 .html 文件一起“发送”到,以便 .html 文件可以通过某个变量访问端口。在我的原始帖子中,我编辑了底部部分,以包括我的服务器如何将 .html 文件发送到客户端。
【解决方案2】:

>>

好的,我让它在 Dotcloud 上工作。我只是发布你们需要知道的内容。 如果您一直在关注此问题,那么最终解决方案即将发布。 我要感谢 dotcloud 的 Ken 让我走上了正确的道路。感谢他 我了解了environments.yml、environments.json 文件。另外,做一个

console.log(process.env);

在服务器端是一个巨大的助手。 KK 解决方案如下:

首先我想让你看看我是如何声明我的需求和变量的:

var webSocketServer = require('websocket').server; // websocket
var server = require('http').createServer();
var expr = require("express"); // load the express module
var xpress = expr(); // xpress now holds the server object

好的,既然你知道这些是什么,我需要告诉你,我决定 使用 ejs 渲染模板。我面临的一个问题是我需要我的客户能够 “知道”在哪个端口上通过 WebSocket 连接到服务器。如果没有 websocket 连接,我还要如何给客户端提供一个像“端口”这样的变量。请记住,端口可能会改变,所以我不能硬编码一个像 50234 这样的端口或者在我的 ws:// url 末尾的东西。解决方案是使用“ejs”。

ejs 是一个模块(即“npm install ejs”)我不会真正解释如何使用它。 不过这里是我以前学的一个网站:http://embeddedjs.com/

以下是您需要了解的一些事项: 当客户将他们的浏览器指向您的 dotcloud url 时,这就是您发送它们的方式 一个文件,就我而言,我将 .html 文件更改为 .ejs 文件,以便可以将其呈现为 一个模板。

xpress.get('/', function(req, res) {
    res.render('game', 
    {
        answer: superCoolPort
    });
});

'game' 意味着在我告诉服务器查找模板的任何文件夹中,都应该有 一个名为 game.ejs 的文件。 请注意我如何使用一些数据渲染名为 game.ejs 的模板。在这种情况下 数据是我的 server.js 文件中名为“superCoolPort”的局部变量。这是什么 该变量是:

var superCoolPort = process.env['DOTCLOUD_WWW_SERVER_PORT'];

好的,现在 express(在我的例子中是“xpress”),需要监听 8080 端口。

xpress.listen(8080);

这不是您的 WebSocket 将尝试连接的端口。这是港口 您的浏览器尝试连接到该页面。但是,Dotcloud 不允许您 在端口 80 上托管任何内容,因此如果您在 8080 上托管它,他们会为您将其重定向到 80。这样就不用在浏览器中输入 url:8080 了。

现在让我解释一下http服务器是如何变成wsServer的。基本上你设置 http服务器并让它监听一个端口。然后你把这个 http 服务器挂载到一个 网络套接字服务器。看到我在顶部声明“服务器”的位置了吗?

这是 http 服务器要监听的端口。注意,这意味着 websocket 服务器也会监听这个端口。

var webSocketsServerPort = process.env['PORT_SERVER'] || 4242;
server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + "The http server is listening on port " + webSocketsServerPort);
});

// WebSocket Server
var wsServer = new webSocketServer({
    // WebSocket server is tied to a HTTP server. WebSocket request is just
    // an enhanced HTTP request.
    httpServer: server
});

在我转到客户端之前,我想让您知道我是如何设置我的快速配置的。

xpress.configure(function() {
     // Sets the directory to look for templates
     xpress.set('views', __dirname + '/public');
     // This line tells Express that we are using the ejs engine to render templates
     xpress.set('view engine', 'ejs');
     xpress.use(expr.static(__dirname + "/public"));
     xpress.set("view options", {layout: false});
});

以上所有内容都是对 server.js 文件的修改。

好的,接下来我会谈谈模板。我曾经有一个名为 game.html 的文件。嗯,我想要 这是一个模板,我可以用一些数据(websocket 的端口号 需要连接)。所以首先我把文件名改成了game.ejs。 然后,我做了一些修改如下:

<body onload="init()">

成为

<body data-port="<%=answer%>" onload="init()">

怎么看onload="init()"?这意味着在页面加载之前不会调用 init。 这很重要,因为当我们要访问端口时,您不能保证 除非您在“init()”中,否则它是可用的。我知道这一点是因为我试图访问 在我定义 init() 之前,它说变量为空。

现在在 init() 内部,您可以像这样访问端口号:

var port = $('body').data('port');

现在我的 client.js 文件可以像这样初始化 websocket 连接:

this.connection = new WebSocket('ws://pirate-captainlonate.dotcloud.com:' + this.thePort);

其中“this.thePort”与上面的“port”相同。

我想让这个解决方案尽可能完整,所以这是我的 dotcloud.yml 文件。它坐 我的 server.js 文件上方的一个目录:

www:
    type: nodejs
    approot: app
    ports:
        server: tcp
    processes:
        app: node app.js
    config:
        node_version: v0.8.x

db:
    type: mongodb

这是我的 package.json 文件。它与我的 server.js 文件(在我的情况下实际上称为 app.js)位于同一目录中:

{
  "name": "app",
  "version": "0.0.0",
  "scripts": {
    "start" : "node app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies":{
      "express" : "",
      "mongodb" : "",
      "fs": "",
      "ejs": "",
      "ws": "",
      "websocket": ""
  },
  "repository": "",
  "author": "",
  "license": "BSD"
}

最后,老实说,我不知道这是否有必要,但这是我的 supervisord.conf 文件。它与 server.js 位于同一目录中。

[program:node]
command = node app.js
directory = /home/dotcloud/current

嗯,我认为这就是一切。 我希望我没有遗漏任何东西。但最终,这些改变正是我所需要的 让我的 nodejs 应用程序使用“websocket”在 Dotcloud 上部署和运行。

【讨论】:

    【解决方案3】:

    看起来您正在尝试访问端口 1337 上的 WebSocket,但您应该尝试通过端口 80。

    this.connection = new WebSocket('ws://pirate-captainlonate.dotcloud.com');
    

    大多数公共平台仅通过端口 80 反向代理您的应用程序。说到,您是否尝试过在 Nodejitsu 上运行您的应用程序? http://nodejitsu.com

    【讨论】:

    • 所以事情是这样的:如果你查看docs.dotcloud.com/0.9/services/nodejs,那么你会看到 dotcloud 要求用户让他们的服务器监听端口 8080,因为端口 80 需要 root 而我们没有 root。果然,尝试这样做会产生:“错误:听 EACCES”。现在,如果 express 在 8080 上侦听并且 http.createServer 在 8080 上侦听,那么您会得到:“错误:侦听 EADDRINUSE”,这是您所期望的,因为有两个东西占用了一个端口。有点像泡菜。 nodejitsu 比 dotcloud 好吗?
    • 因此,如果服务器侦听端口 8080,而您的 websocketserver 侦听不同的端口,那么一切都会正常。这样做是有道理的。但是当我尝试它时,我完全没有错误。页面加载正常,但未建立 websocket 连接...
    • 我不确定该代码是否适用于 nodejitsu,如果我错了,请纠正我,但根据此链接:handbook.nodejitsu.com/a-quickstart/… 它说您不能听多个端口每个服务一次,上面的代码想要一次监听 2 个不同的端口。也许你可以使用代理之类的?
    猜你喜欢
    • 1970-01-01
    • 2011-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-28
    • 2017-11-16
    • 2020-02-12
    • 1970-01-01
    相关资源
    最近更新 更多