Apache Node.js Socket.io

Apache Node.js Socket.io_第1张图片

由于系统是WAMP,由外包过渡过来的。在Apache设置反向代理比较不友善;且自chrome4.7以后,大部分socket请求必须基于SSL协议传输。


前提:给项目加个长连接,做个进度条。

困境:请求协议为HTTP, 如果加入SSL协议,这不仅增加一笔费用;对旧项目并不友好,php项目全是基于http的,而已Apache设置SSL估计又是折磨人。

解决:使用Apache设置反向代理,解决浏览器无法连接websocket的问题;使用localhost之前请求来解决安全性问题。


本文内容

  • 项目环境技术栈
  • 后端Socket服务设计
  • 试错过程
  • 提交方案
  • 运行项目
  • 参考网站

1.项目环境技术栈

  • 构架时,后端代理前端压缩包文件。
  • 长连接使用socket.io。

2.后端Socket服务设计

后端对外不开放,不需要使用反向代理。内容如下所示(不全):

const express = require('express');
const http = require('http');
const socketio = require('socket.io');

const app = express();
const server = http.Server(app);
const io = socketio(server);
//加载前端页面
app.use(express.static(path.join(__dirname, 'build')));

io.on('connection', (sock) => {
  console.log('Client connected');

  sock.on('heartbeat', (payload) => {
    payload.nodeName = name;
    sock.emit('heartbeat', payload);
  });

  sock.on('disconnect', () => {
    console.log('Socket Disconnected');
  });
});

server.listen(+port, '0.0.0.0', (err) => {
  console.log(`Node [${name}] listens on http://127.0.0.1:${port}.`);
});
  • Socket.io和Express一起使用。
  • 命令空间设计

3.试错过程

由于之前没做过,好尴尬了。看了几个小时socket.io文档直接使用了,所以踩的坑会比较多。

  • 由于chrome4.7后,对安全策略进行变化 。先了解浏览器对websocket的长连接的策略。

node代理
使用node http-proxy-middleware代理socket过程,在本地(都是基本localhost)完美运行。然后上传运行代理,并开放外网端口,运行结果如下所示:

[HPM] Proxy created: /  ->  http://localhost:8787
[HPM] Subscribed to http-proxy events:  [ 'error', 'close' ]
[HPM] Proxy created: /  ->  http://localhost:8787
[HPM] Subscribed to http-proxy events:  [ 'error', 'close' ]
  • 显示代理成功,在服务器测试socket连接正常。但使用外网访问时,如下的错误
Uncaught (in promise) DOMException: Only secure origins are allowed. http://goo.gl/lq4gCo
  • 分析过程:
  1. 在服务器端测试时,可以通过是因为:它们之间是localhost请求,能过浏览器安全策略。
  2. 服务器外网地址跟localhost在服务器在有网卡代理,localhost与外网交互,没安全策略的,它也相当于一个本地请求。
  3. 当在外网访问网页端时,网页在"/"链接中,地址是外网地址。外网与localhost将无法通过浏览器安全策略。

使用Apache代理过程

  • 先实现一个小目标,实现一个简单的Http反向代理。
#不给别人get到你的代理
ProxyRequests off 
    
        ProxyPass http://127.0.0.1:30003/
        ProxyPassReverse /
    
  • 发现没反应,ngnix直接用的尴尬,why not ok? 查下资料,才知道要加载 proxy_module, proxy_http_module。

  • 那么接下去代理,想下Apache代理比较全的帖子,我擦,完全没有提到Socket,就加入个mod_proxy_connect,说不定以后能使用SSL呢。
  • 那只有去官网找,意淫术,socket的请求协议为WS,去httpd.conf搜下(找下)proxy-ws*,果然找到mod_proxy_wstunnel,就是这货了。
  • 接下去的看,只能在2.4.5以上版本使用。呸,然后查下2.4.3才发行。直接用别管它。
    Compatibility: |Available in httpd 2.4.5 and later
  • 在httpd.conf文件中,加载这模块
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

WAMP

  • 有时,没什么毛病,它就是不给你运行。这个迷之原因,炸了没。别扯什么底层代理实现过程。
  • 使用颜色分析过程,一般是:红色->橙色->绿色。不行的话,红色那状态会比较快,然后停到橙色。
  • 使用重复启动法,重复重启。当红色停留比较久时,那就可能成功了。

4.提交方案

下面将使用Apache反向代理,使网页端与API接口变成localhost间的请求,原理图如下所示,网页端服务跟API服务将在内部服务器中:

Apache Node.js Socket.io_第2张图片

1. 将网页端服务使用反向代理出来

  • Apache 配置如下所示:
    标志RewriteEngine, Rewrite*, 规则NC, N* P*
//httpd.conf
Listen 30003
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule proxy_http_module modules/mod_proxy_http.so

//httpd-vhosts.conf


    RewriteEngine On
    RewriteCond %{HTTP:Connection} Upgrade [NC]
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteRule /(.*) ws://127.0.0.1:3030/$1 [P,L]

    ProxyRequests off
    
        ProxyPass http://127.0.0.1:3030/
        ProxyPassReverse /
    


2.前后端分离,前端使用socket.io-client,代码如下所示:

import openSocket from 'socket.io-client';
const socket = openSocket(); //不用设置任意参数

 socket.on('heartbeat', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });

5.运行项目

  • 访问服务器端口30003地址,其实是反向访问localhost:3000。localhost地址之间socket长连接无fuck。
  • 不安全是Http协议的长连接。


    Apache Node.js Socket.io_第3张图片

6.参考网站

  • chrome安全策略,解决方案,本文参考方案:https://webrtchacks.com/chrome-secure-origin-https/
  • 反向代理:https://www.cnblogs.com/anruy/p/4989161.html
  • 代理Http所需的模块:https://stackoverflow.com/questions/9831594/apache-and-node-js-on-the-same-server
  • Apache代理讲解:http://www.apachetutor.org/admin/reverseproxies
  • 标志Rewrite*: https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html
  • 规则N, P : https://httpd.apache.org/docs/2.4/rewrite/flags.html
  • mod_proxy_wstunnel模块用于配置socket:https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html
  • Apache httpd.conf配置:https://stackoverflow.com/questions/29792372/apache2-websockets-reverse-proxy-on-same-url

如果socket请求跨源,一定要有SSL设置?,不太清楚

你可能感兴趣的:(Apache Node.js Socket.io)