Размещение сервера nodejs на dotcloud
Я пытаюсь разместить приложение nodejs на хостинге "dotcloud". Мой nodejs использует пакет "websocket" для обработки сообщений. то есть. npm установить websocket
Мое приложение отлично работает, когда оно работает на локальном хосте на моем ноутбуке. Но когда я развертываю приложение на dotcloud, оно не работает правильно.
Вот что происходит: вы указываете свой браузер на URL в dotcloud: pirate-captainlonate.dotcloud.com
Затем express обрабатывает запрос GET с помощью express.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
});
Этого должно быть достаточно, чтобы показать вам, ребята, как это работает. Теперь один из вас, вероятно, спросит, что показывает ">> logts dotcloud"?
[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');
});
3 ответа
Похоже, вы пытаетесь использовать 2 http порта для своей службы, и dotCloud поддерживает только 1 из коробки, поэтому вам нужно сообщить им, что вы хотите иметь еще один, добавив небольшой фрагмент в свой dotcloud.yml
Вот пример dotcloud.yml
который запрашивает второй порт 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.json
, environment.yml
файлы, переменные оболочки ENV или войдите в панель управления dotCloud, щелкните свое приложение, а затем вкладку "Среда", чтобы увидеть список переменных вашего приложения.
Если вы сделаете эти три изменения, ваши проблемы должны исчезнуть.
Если вам нужно больше примеров кода, пожалуйста, ознакомьтесь с этим репозиторием на github, в котором вы делаете нечто похожее на то, что вы пытаетесь сделать.
<<< Оригинальный постер здесь >>>
Хорошо, я заставил это работать на Dotcloud. Я просто собираюсь опубликовать то, что вы, ребята, должны знать. Если вы следили за этой проблемой, окончательное решение будет опубликовано. Я хочу поблагодарить Кена из dotcloud за то, что он направил меня по правильному пути. Благодаря ему я узнал о файлах environment.yml, environment.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. Без подключения через веб-сокет, как еще я собирался передать клиенту переменную типа "порт". Имейте в виду, что порт может измениться, поэтому я не мог просто жестко закодировать порт, такой как 50234 или что-то в конце моего ws:// url. Решение было использовать "ejs".
ejs - это модуль (то есть "npm install ejs"). Я не собираюсь объяснять, как его использовать. Но вот сайт, на котором я учился: http://embeddedjs.com/
Вот некоторые вещи, которые вам нужно знать: когда клиент указывает свой браузер на ваш URL-адрес dotcloud, именно так вы отправляете им файл, в моем случае я изменил свой файл.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" совпадает с "портом" сверху.
Я хочу сделать это решение как можно более полным, поэтому вот мой файл 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.
Похоже, вы пытаетесь получить доступ к WebSocket через порт 1337, но вы должны пытаться через порт 80.
this.connection = new WebSocket('ws://pirate-captainlonate.dotcloud.com');
Большинство общедоступных платформ используют обратный прокси-сервер для вашего приложения через порт 80. Кстати, вы пытались запустить свое приложение на Nodejitsu? http://nodejitsu.com/