Node.js - 当由 Nginx 反向代理提供服务时,Websocket 拒绝打开连接
Node.js - Websocket refuses to open a connection when served by Nginx reverse proxy
目前我正在尝试设置一个简单的聊天应用程序。我正在使用 total.js 框架。我的 Node.js 程序在 [http]://127.0.0.1:8000/ 上运行。只要请求 URI 与加载页面的 HTML 代码中指定的确切 URI 匹配,此方法就有效。例如,转到 [http]://localhost:8000/ 将加载 html 页面,但所有功能将无法正常工作,而 [http]://127.0.0.1:8000 将按预期工作。
我在尝试将 Nginx 设置为反向代理时发现了这一点,因此我可以通过转到 [http]://127.0.0.1:80/ 来访问它。 html 页面会在此处加载,但聊天功能无法使用。
此聊天应用是 total.js 示例的一部分。
这是创建 websocket 的 index.html 文件:
<div class="mb5">
<button name="open">CONNECT</button>
</div>
<div>
<button name="close" disabled="disabled">DISCONNECT</button>
</div>
<br />
<div>
<input type="text" name="message" maxlength="200" style="width:500px" />
<button name="send" disabled="disabled">SEND</div>
</div>
<br />
<div>
<textarea id="output" style="width:620px;height:300px" readonly="readonly"></textarea>
</div>
<br />
<div>
<input type="text" value="" name="username" maxlength="20" style="width:200px" />
<button name="rename" disabled="disabled">RENAME</div>
</div>
<script type="text/javascript">
var socket = null;
$(document).ready(function() {
$('button').bind('click', function() {
if (this.name === 'rename') {
var value = $('input[name="username"]').val();
if (value.length > 0)
socket.send(encodeURIComponent(JSON.stringify({
username: value
})));
return;
}
if (this.name === 'send') {
console.log('send');
send();
return;
}
if (this.name === 'open') {
connect();
return;
}
console.log('disconnect');
disconnect();
});
});
function connect() {
if (socket !== null)
return;
$('button[name="open"]').attr('disabled', true);
$('button[name="close"],button[name="send"],button[name="rename"]').attr('disabled', false);
socket = new WebSocket('ws://127.0.0.1:8000/');
socket.onopen = function() {
console.log('open');
};
socket.onmessage = function(e) {
var el = $('#output');
var m = JSON.parse(decodeURIComponent(e.data)).message;
el.val(m + '\n' + el.val());
};
socket.onclose = function(e) {
// e.reason ==> total.js client.close('reason message');
$('button[name="open"]').attr('disabled', false);
};
}
function send() {
var el = $('input[name="message"]');
var msg = el.val();
if (socket !== null && msg.length > 0)
socket.send(encodeURIComponent(JSON.stringify({
message: msg
})));
el.val('');
}
function disconnect() {
if (socket === null)
return;
$('button[name="close"],button[name="send"],button[name="rename"]').attr('disabled', true);
$('button[name="open"]').attr('disabled', false);
socket.close();
socket = null;
}
</script>
这听起来像是同源保护。
除非您的 socket.io 服务器支持 COR 并允许从跨源域访问,否则当网页从 localhost:8000
加载时,浏览器将不允许连接到 127.0.0.1:8000
,反之亦然反之亦然。您要连接的域必须与网页的域匹配,除非您的服务器支持 CORS 并明确允许跨域连接。
而且,即使 localhost:8000
和 127.0.0.1:8000
实际上可能是同一台服务器,浏览器也不允许。
解决您的特定问题的通常方法是仅使用 Javascript 中的 window.location
来获取当前页面 URL 中的主机名的形式并构建您的 URL 使用该主机名,因此您确保在页面 URL.
中使用相同的主机名
例如:
socket = new WebSocket('ws://' + window.location.host + '/');
我想这不言而喻,您的 nginx 代理也必须专门配置为支持 webSocket 连接。
目前我正在尝试设置一个简单的聊天应用程序。我正在使用 total.js 框架。我的 Node.js 程序在 [http]://127.0.0.1:8000/ 上运行。只要请求 URI 与加载页面的 HTML 代码中指定的确切 URI 匹配,此方法就有效。例如,转到 [http]://localhost:8000/ 将加载 html 页面,但所有功能将无法正常工作,而 [http]://127.0.0.1:8000 将按预期工作。
我在尝试将 Nginx 设置为反向代理时发现了这一点,因此我可以通过转到 [http]://127.0.0.1:80/ 来访问它。 html 页面会在此处加载,但聊天功能无法使用。
此聊天应用是 total.js 示例的一部分。
这是创建 websocket 的 index.html 文件:
<div class="mb5">
<button name="open">CONNECT</button>
</div>
<div>
<button name="close" disabled="disabled">DISCONNECT</button>
</div>
<br />
<div>
<input type="text" name="message" maxlength="200" style="width:500px" />
<button name="send" disabled="disabled">SEND</div>
</div>
<br />
<div>
<textarea id="output" style="width:620px;height:300px" readonly="readonly"></textarea>
</div>
<br />
<div>
<input type="text" value="" name="username" maxlength="20" style="width:200px" />
<button name="rename" disabled="disabled">RENAME</div>
</div>
<script type="text/javascript">
var socket = null;
$(document).ready(function() {
$('button').bind('click', function() {
if (this.name === 'rename') {
var value = $('input[name="username"]').val();
if (value.length > 0)
socket.send(encodeURIComponent(JSON.stringify({
username: value
})));
return;
}
if (this.name === 'send') {
console.log('send');
send();
return;
}
if (this.name === 'open') {
connect();
return;
}
console.log('disconnect');
disconnect();
});
});
function connect() {
if (socket !== null)
return;
$('button[name="open"]').attr('disabled', true);
$('button[name="close"],button[name="send"],button[name="rename"]').attr('disabled', false);
socket = new WebSocket('ws://127.0.0.1:8000/');
socket.onopen = function() {
console.log('open');
};
socket.onmessage = function(e) {
var el = $('#output');
var m = JSON.parse(decodeURIComponent(e.data)).message;
el.val(m + '\n' + el.val());
};
socket.onclose = function(e) {
// e.reason ==> total.js client.close('reason message');
$('button[name="open"]').attr('disabled', false);
};
}
function send() {
var el = $('input[name="message"]');
var msg = el.val();
if (socket !== null && msg.length > 0)
socket.send(encodeURIComponent(JSON.stringify({
message: msg
})));
el.val('');
}
function disconnect() {
if (socket === null)
return;
$('button[name="close"],button[name="send"],button[name="rename"]').attr('disabled', true);
$('button[name="open"]').attr('disabled', false);
socket.close();
socket = null;
}
</script>
这听起来像是同源保护。
除非您的 socket.io 服务器支持 COR 并允许从跨源域访问,否则当网页从 localhost:8000
加载时,浏览器将不允许连接到 127.0.0.1:8000
,反之亦然反之亦然。您要连接的域必须与网页的域匹配,除非您的服务器支持 CORS 并明确允许跨域连接。
而且,即使 localhost:8000
和 127.0.0.1:8000
实际上可能是同一台服务器,浏览器也不允许。
解决您的特定问题的通常方法是仅使用 Javascript 中的 window.location
来获取当前页面 URL 中的主机名的形式并构建您的 URL 使用该主机名,因此您确保在页面 URL.
例如:
socket = new WebSocket('ws://' + window.location.host + '/');
我想这不言而喻,您的 nginx 代理也必须专门配置为支持 webSocket 连接。