3

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

我的应用程序在我的笔记本电脑上的 localhost 上运行时效果很好。但是当我在 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');
});
4

3 回答 3

2

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

这是一个dotcloud.yml请求第二个名为server的 tcp 端口的示例

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

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

这是一个片段,它将从 ENV 获取您的端口,当不存在时它将默认为 4242,因此您仍然可以在本地运行。

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

如果您想知道我是如何获得 ENV 变量名称的,这很简单。它将是 PORT_,然后是来自dotcloud.yml. 由于我使用上面的服务器,它变成了 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.jsonenvironment.yml文件、shell ENV 变量中获取它,或登录 dotCloud 仪表板,单击您的应用程序,然后单击环境选项卡以查看您的应用程序变量列表。

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

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

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

于 2013-02-16T12:22:53.937 回答
1

<<<这里是原海报>>>

好的,我让它在 Dotcloud 上工作。我只是发布你们需要知道的内容。如果您一直在关注此问题,那么最终解决方案即将发布。我要感谢 dotcloud 的 Ken 让我走上了正确的道路。感谢他,我了解了 environment.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.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 服务器挂载到 websocket 服务器。看到我在顶部声明“服务器”的位置了吗?

这是 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

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

于 2013-02-18T22:55:45.247 回答
-1

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

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

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

于 2013-02-16T04:39:30.750 回答