NGROK + WEB-SERVER + NODE.JS + WEBSOCKET + NPM
Posted
技术标签:
【中文标题】NGROK + WEB-SERVER + NODE.JS + WEBSOCKET + NPM【英文标题】: 【发布时间】:2018-11-29 23:11:22 【问题描述】:我在 localhost 上有一个 Web 服务器,我用手机通过 ngrock 连接到这个服务器。在这里非常好,因为 ngrock 创建了一个 url,例如 http://94815c96.ngrok.io,它将我重定向到 localhost:8888,在那里我可以看到我的项目和文件。
然后我需要通过 websocket 连接我的网络服务器并创建一个聊天应用程序,为此我安装了 npm 和 node.js 并运行命令 node filename.js,这个 filename.js 文件创建了一个套接字在端口 1337 上侦听,并在 Web 服务器一侧打开端口 1337 上的 Websocket。如果我通过本地设备上的 Web 浏览器进行操作,它可以工作,但是当我通过带有 ngrock url 的手机尝试它时,它返回一个无法连接到 WebSocket 服务器的错误。
我使用的代码很简单。我有一个名为 frontend.html 的 html 来查看和输出聊天应用程序,另一个名为 chat-client.js 的文件在端口 1337 上打开与 websocket 的连接,最后一个文件名为 chat-server.js 侦听端口 1337。每个文件的代码如下:
前端.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebSockets - Simple chat</title>
<style>
* font-family:tahoma; font-size:12px; padding:0px; margin:0px;
p line-height:18px;
div width:500px; margin-left:auto; margin-right:auto;
#content padding:5px; background:#ddd; border-radius:5px; overflow-y: scroll;
border:1px solid #CCC; margin-top:10px; height: 160px;
#input border-radius:2px; border:1px solid #ccc;
margin-top:10px; padding:5px; width:400px;
#status width:88px; display:block; float:left; margin-top:15px;
</style>
</head>
<body>
<div id="content"></div>
<div>
<span id="status">Connecting...</span>
<input type="text" id="input" disabled="disabled" />
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="./chat-frontend.js"></script>
</body>
</html>
聊天客户端.js:
$(function ()
"use strict";
// for better performance - to avoid searching in DOM
var content = $('#content');
var input = $('#input');
var status = $('#status');
// my color assigned by the server
var myColor = false;
// my name sent to the server
var myName = false;
// if user is running mozilla then use it's built-in WebSocket
window.WebSocket = window.WebSocket || window.MozWebSocket;
// if browser doesn't support WebSocket, just show some notification and exit
if (!window.WebSocket)
content.html($('<p>', text: 'Sorry, but your browser doesn\'t '
+ 'support WebSockets.' ));
input.hide();
$('span').hide();
return;
// open connection
var connection = new WebSocket('ws://127.0.0.1:1337');
connection.onopen = function ()
// first we want users to enter their names
input.removeAttr('disabled');
status.text('Choose name:');
;
connection.onerror = function (error)
// just in there were some problems with conenction...
content.html($('<p>', text: 'Sorry, but there\'s some problem with your '
+ 'connection or the server is down.' ));
;
// most important part - incoming messages
connection.onmessage = function (message)
// try to parse JSON message. Because we know that the server always returns
// JSON this should work without any problem but we should make sure that
// the massage is not chunked or otherwise damaged.
try
var json = JSON.parse(message.data);
catch (e)
console.log('This doesn\'t look like a valid JSON: ', message.data);
return;
// NOTE: if you're not sure about the JSON structure
// check the server source code above
if (json.type === 'color') // first response from the server with user's color
myColor = json.data;
status.text(myName + ': ').css('color', myColor);
input.removeAttr('disabled').focus();
// from now user can start sending messages
else if (json.type === 'history') // entire message history
// insert every single message to the chat window
for (var i=0; i < json.data.length; i++)
addMessage(json.data[i].author, json.data[i].text,
json.data[i].color, new Date(json.data[i].time));
else if (json.type === 'message') // it's a single message
input.removeAttr('disabled'); // let the user write another message
addMessage(json.data.author, json.data.text,
json.data.color, new Date(json.data.time));
else
console.log('Hmm..., I\'ve never seen JSON like this: ', json);
;
/**
* Send mesage when user presses Enter key
*/
input.keydown(function(e)
if (e.keyCode === 13)
var msg = $(this).val();
if (!msg)
return;
// send the message as an ordinary text
connection.send(msg);
$(this).val('');
// disable the input field to make the user wait until server
// sends back response
input.attr('disabled', 'disabled');
// we know that the first message sent from a user their name
if (myName === false)
myName = msg;
);
/**
* This method is optional. If the server wasn't able to respond to the
* in 3 seconds then show some error message to notify the user that
* something is wrong.
*/
setInterval(function()
if (connection.readyState !== 1)
status.text('Error');
input.attr('disabled', 'disabled').val('Unable to comminucate '
+ 'with the WebSocket server.');
, 3000);
/**
* Add message to the chat window
*/
function addMessage(author, message, color, dt)
content.prepend('<p><span style="color:' + color + '">' + author + '</span> @ ' +
+ (dt.getHours() < 10 ? '0' + dt.getHours() : dt.getHours()) + ':'
+ (dt.getMinutes() < 10 ? '0' + dt.getMinutes() : dt.getMinutes())
+ ': ' + message + '</p>');
);
聊天服务器.js
// http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
"use strict";
// Optional. You will see this name in eg. 'ps' or 'top' command
process.title = 'node-chat';
// Port where we'll run the websocket server
var webSocketsServerPort = 1337;
// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');
/**
* Global variables
*/
// latest 100 messages
var history = [ ];
// list of currently connected clients (users)
var clients = [ ];
/**
* Helper function for escaping input strings
*/
function htmlEntities(str)
return String(str).replace(/&/g, '&').replace(/</g, '<')
.replace(/>/g, '>').replace(/"/g, '"');
// Array with some colors
var colors = [ 'red', 'green', 'blue', 'magenta', 'purple', 'plum', 'orange' ];
// ... in random order
colors.sort(function(a,b) return Math.random() > 0.5; );
/**
* HTTP server
*/
var server = http.createServer(function(request, response)
// Not important for us. We're writing WebSocket server, not HTTP server
);
server.listen(webSocketsServerPort, function()
console.log((new Date()) + " 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. For more info http://tools.ietf.org/html/rfc6455#page-6
httpServer: server
);
// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request)
console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
// accept connection - you should check 'request.origin' to make sure that
// client is connecting from your website
// (http://en.wikipedia.org/wiki/Same_origin_policy)
var connection = request.accept(null, request.origin);
// we need to know client index to remove them on 'close' event
var index = clients.push(connection) - 1;
var userName = false;
var userColor = false;
console.log((new Date()) + ' Connection accepted.');
// send back chat history
if (history.length > 0)
connection.sendUTF(JSON.stringify( type: 'history', data: history ));
// user sent some message
connection.on('message', function(message)
if (message.type === 'utf8') // accept only text
if (userName === false) // first message sent by user is their name
// remember user name
userName = htmlEntities(message.utf8Data);
// get random color and send it back to the user
userColor = colors.shift();
connection.sendUTF(JSON.stringify( type:'color', data: userColor ));
console.log((new Date()) + ' User is known as: ' + userName
+ ' with ' + userColor + ' color.');
else // log and broadcast the message
console.log((new Date()) + ' Received Message from '
+ userName + ': ' + message.utf8Data);
// we want to keep history of all sent messages
var obj =
time: (new Date()).getTime(),
text: htmlEntities(message.utf8Data),
author: userName,
color: userColor
;
history.push(obj);
history = history.slice(-100);
// broadcast message to all connected clients
var json = JSON.stringify( type:'message', data: obj );
for (var i=0; i < clients.length; i++)
clients[i].sendUTF(json);
);
// user disconnected
connection.on('close', function(connection)
if (userName !== false && userColor !== false)
console.log((new Date()) + " Peer "
+ connection.remoteAddress + " disconnected.");
// remove user from the list of connected clients
clients.splice(index, 1);
// push back user's color to be reused by another user
colors.push(userColor);
);
);
Command to execute ngrok
Execute node with chat-server.js
Error returned by ngrok
【问题讨论】:
【参考方案1】:您需要向世界公开您的第二个端口 1337,该端口由 WebSockets 使用。您需要有 2 个单独的 ngrok 实例运行并转发 1337 和 8888 端口。同样在 chat-client.js 行“ws://127.0.0.1:1337”应该更改为新的 ngrok 转发 url(例如 ws://111111.ngrok.io)
【讨论】:
以上是关于NGROK + WEB-SERVER + NODE.JS + WEBSOCKET + NPM的主要内容,如果未能解决你的问题,请参考以下文章
wbhook 通过 ngrok 连接到本地 node.js 服务器,服务触发 Webhooks 需要密码吗?
Node.js,基于 socket-io 的一对一聊天引擎在本地运行良好,但在使用 ngrok 在不同笔记本电脑上运行时无法运行