2013-02-16 2 views
3

Я пытаюсь разместить приложение nodejs в службе хостинга «dotcloud». Мой nodejs использует пакет «websocket» для обработки сообщений. т.е. npm install websocketХостинг сервера nodejs на dotcloud

Мое приложение отлично работает, когда оно работает на localhost на моем ноутбуке. Но когда я развертываю приложение в dotcloud, он работает неправильно.

Вот что происходит: Вы указываете ваш браузер URL-адрес на dotcloud: pirate-captainlonate.dotcloud.com

Затем экспресс обрабатывает запрос GET с express.get («/» .. .....) {} Экспресс обслуживает страницу .html для клиента, как и следовало ожидать. Файл .html в свою очередь пытается установить соединение с сервером. Опять же, я могу получить , чтобы это было нормально работать на моей локальной машине. Однако связь не устанавливается. В частности, dotcloud определенно служит мне .html-файлу, но файл .html не устанавливает соединение с сервером. Но 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) 

Хорошо, хорошо, мне бы очень хотелось, чтобы эта работа работала. Я был на этом вечно. Дайте мне знать, если что-то еще вам нужно, чтобы помочь мне ответить на мой вопрос.

Спасибо,

--Nathan

Добавление: Это как сервер отправляет файл HTML.

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

Отличный вопрос, много информации, что позволило легко найти вашу проблему. В основном вам нужен второй порт http. Я объясню, как это сделать в моем ответе ниже. –

ответ

-1

Похоже, вы пытаетесь получить доступ к WebSocket на порту 1337, но вы должны пытаться через порт 80.

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

Большинство общественных платформ только обратный прокси-сервер для вашего приложения через порт 80 Говоря о том, пытались ли вы запустить приложение на Nodejitsu?http://nodejitsu.com

+0

Итак, вот что: если вы посмотрите http://docs.dotcloud.com/0.9/services/nodejs/, то вы увидите, что dotcloud требует от пользователей, чтобы их сервер прослушивал порт 8080, так как порт 80 требует root, и мы не имеют корня. Конечно, попытка: «Ошибка: прослушивание EACCES». Теперь, если экспресс прислушивается к 8080 И http.createServer слушает 8080, вы получаете: «Ошибка: слушайте EADDRINUSE», который вы ожидаете, поскольку две вещи занимают один порт. Это своего рода рассол. Является ли nodejitsu лучше, чем dotcloud? – Captainlonate

+0

Итак, если сервер прослушивает порт 8080, и ваш сервер websocketserver прослушивает другой порт, все должно получиться. Имеет смысл, что это сработает. Но когда я пытаюсь, я не получаю никаких ошибок.Страница загружается как обычно, но соединение с websocket не установлено ... – Captainlonate

+0

Я не уверен, что этот код будет работать на nodejitsu, исправьте меня, если я ошибаюсь, но по этой ссылке: https: // handbook .nodejitsu.com/a-quickstart/faq # faq-how-can-i-make-my-app-use-a-port-other-than-port-80 говорит, что вы не можете слушать более одного порта за один раз за услугу, а код выше хочет прослушивать сразу два разных порта. Может быть, вы могли бы использовать прокси-сервер или что-то еще? –

2

Похоже, вы пытаетесь использовать 2 порта HTTP для вашей службы, а dotCloud поддерживает только 1 из коробки, поэтому вам нужно сообщить им, что вы хотите иметь еще один, добавив небольшой фрагмент в свой dotcloud.yml

Вот пример dotcloud.yml, который просит второго порта TCP называется сервер

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

После того, как вы добавите это и толчок, ваш сервер будет предоставлен 2-й TCP-порт можно использовать для вашего сервер, вам просто нужно узнайте, какой порт, который получает значение из вашего файла среды.

Вот фрагмент, который получит ваш порт из ENV, по умолчанию он будет равен 4242, если он не существует, поэтому вы все еще можете выполнять локально.

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

Если вам интересно, как я получил имя переменной ENV, это просто. это будет PORT_, а затем верхняя строка имени из dotcloud.yml. Поскольку я использовал сервер выше, он стал PORT_SERVER, если бы я использовал узел, это было бы PORT_NODE, так что поставьте то, что хотите, но убедитесь, что эти значения совпадают.

Клиент:

Чтобы узнать, какой порт нужно подключить к на клиентском компьютере, Вы должны были бы вернуться к своим переменным окружения снова. На этот раз вы ищете переменную, которая выглядит так: DOTCLOUD_APP_SERVER_PORT. Важно: Ваше имя переменной может отличаться

Как я получил, что envirornment имя переменной?

Имя переменной выглядит так: DOTCLOUD_{{app_name}}_{{port_name}}_PORT все прописные. Замените {{variable}} на информацию ниже.

{{app_name}} = имя вашего приложения с вашего dotcloud.yml, в приведенном выше примере это app {{port_name}} имя = порт, server в dotcloud.yml примере выше.

Чтобы найти это, вы можете получить его из своих приложений environment.json, environment.yml файлов, переменные ENV оболочки или войти в панель инструментов dotCloud, щелкнуть мышью по вашему приложению, а затем вкладку «Окружающая среда», чтобы просмотреть список ваших переменных приложения.

Если вы сделаете эти три изменения, ваши проблемы должны исчезнуть.

Если вам нужно больше примеров кода, ознакомьтесь с этим реестром github, который делает что-то похожее на то, что вы пытаетесь сделать.

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

+0

Хорошо, но если я это сделаю, то какой порт мой клиент пытается установить соединение? Я не пробовал ни одного порта, 4242, 1337, затем я попытался сделать какой-то mumbo jumbo, и результаты были удивительными. Не имеет значения, что я ввел в вызов конструктора WebSocket(), каждый раз получал тот же результат: никаких ошибок, не установлено соединение. – Captainlonate

+0

@Captainlonate Я обновил ответ, чтобы включить, как узнать, какой порт вы можете подключить от вашего клиента. –

+0

Alright Ken, статус обновления: я пробовал то, что вы сказали, но я не могу использовать process.env [] в файле client.js. Независимо от того, что находится в скобках «[]», вызов функции «process.env» не распознается. Консоль Chrome говорит: «Неиспользуемый ReferenceError: процесс не определен. Для ясности это то, что строка в моем файле client.js говорит: var thePort = process.env ['DOTCLOUD_APP_SERVER_PORT']; Придерживайтесь меня, Кен, я отчаянно хочу, чтобы это сработало. – Captainlonate

1

< < < Оригинальный плакат Здесь >>>

Хорошо, я получил эту работу на Dotcloud. Я просто собираюсь опубликовать то, что вам нужно знать. Если вы столкнулись с этой проблемой, окончательное решение будет опубликовано. Я хочу поблагодарить Кена из dotcloud за то, что вы на правильном пути. Благодаря ему Я узнал о файлах environment.yml, environment.json. Кроме того, выполнение операции

console.log(process.env); 

На стороне сервера был помощник HUUGE. 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 

Хорошо, теперь, когда вы знаете, что эти вещи, я должен сказать вам, что я решил to Используйте 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']; 

Хорошо, теперь выражают («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. Ну, я хотел, чтобы был шаблоном, который я мог бы отобразить с некоторыми данными (номер порта, который должен подключаться к веб-узлу ). Поэтому сначала я изменил имя файла на game.ejs. Затем я сделал некоторые изменения следующим образом:

<body onload="init()"> 

стал

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

посмотреть, как OnLoad = "Init()"? Это означает, что init не будет вызываться до загрузки страницы. Это важно, потому что, когда мы хотим получить доступ к порту, вы не можете гарантировать, что он доступен, если вы не находитесь внутри «init()». Я знаю это, потому что я пытался получить доступ к до того, как я определил init(), и сказал, что переменная имеет значение null.

Теперь внутри 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" 
} 

Наконец, я честно не знаю, если это необходимо или нет, но здесь мой файл superisord.conf. Он находится в том же каталоге, что и server.js.

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

Ну, я думаю, что это все. Надеюсь, я ничего не оставил. В конечном счете, хотя эти изменения были необходимы мне , чтобы получить приложение nodejs с помощью «websocket» для развертывания и запуска на Dotcloud.

Смежные вопросы