
由于系統(tǒng)是WAMP,由外包過渡過來的。在Apache設(shè)置反向代理比較不友善;且自chrome4.7以后,大部分socket請求必須基于SSL協(xié)議傳輸。
前提:給項目加個長連接,做個進度條。
困境:請求協(xié)議為HTTP, 如果加入SSL協(xié)議,這不僅增加一筆費用;對舊項目并不友好,php項目全是基于http的,而已Apache設(shè)置SSL估計又是折磨人。
解決:使用Apache設(shè)置反向代理,解決瀏覽器無法連接websocket的問題;使用localhost之前請求來解決安全性問題。
本文內(nèi)容
- 項目環(huán)境技術(shù)棧
- 后端Socket服務(wù)設(shè)計
- 試錯過程
- 提交方案
- 運行項目
- 參考網(wǎng)站
1.項目環(huán)境技術(shù)棧
- 構(gòu)架時,后端代理前端壓縮包文件。
- 長連接使用socket.io。
2.后端Socket服務(wù)設(shè)計
后端對外不開放,不需要使用反向代理。內(nèi)容如下所示(不全):
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一起使用。
- 命令空間設(shè)計
3.試錯過程
由于之前沒做過,好尷尬了??戳藥讉€小時socket.io文檔直接使用了,所以踩的坑會比較多。
- 由于chrome4.7后,對安全策略進行變化 。先了解瀏覽器對websocket的長連接的策略。
node代理
使用node http-proxy-middleware代理socket過程,在本地(都是基本localhost)完美運行。然后上傳運行代理,并開放外網(wǎng)端口,運行結(jié)果如下所示:
[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' ]
- 顯示代理成功,在服務(wù)器測試socket連接正常。但使用外網(wǎng)訪問時,如下的錯誤:
Uncaught (in promise) DOMException: Only secure origins are allowed. http://goo.gl/lq4gCo
- 分析過程:
- 在服務(wù)器端測試時,可以通過是因為:它們之間是localhost請求,能過瀏覽器安全策略。
- 服務(wù)器外網(wǎng)地址跟localhost在服務(wù)器在有網(wǎng)卡代理,localhost與外網(wǎng)交互,沒安全策略的,它也相當于一個本地請求。
- 當在外網(wǎng)訪問網(wǎng)頁端時,網(wǎng)頁在"/"鏈接中,地址是外網(wǎng)地址。外網(wǎng)與localhost將無法通過瀏覽器安全策略。
使用Apache代理過程
- 先實現(xiàn)一個小目標,實現(xiàn)一個簡單的Http反向代理。
#不給別人get到你的代理
ProxyRequests off
<Location />
ProxyPass http://127.0.0.1:30003/
ProxyPassReverse /
</Location>
- 發(fā)現(xiàn)沒反應,ngnix直接用的尷尬,why not ok? 查下資料,才知道要加載 proxy_module, proxy_http_module。
- 那么接下去代理,想下Apache代理比較全的帖子,我擦,完全沒有提到Socket,就加入個mod_proxy_connect,說不定以后能使用SSL呢。
- 那只有去官網(wǎng)找,意淫術(shù),socket的請求協(xié)議為WS,去httpd.conf搜下(找下)proxy-ws*,果然找到mod_proxy_wstunnel,就是這貨了。
- 接下去的看,只能在2.4.5以上版本使用。呸,然后查下2.4.3才發(fā)行。直接用別管它。
Compatibility: |Available in httpd 2.4.5 and later - 在httpd.conf文件中,加載這模塊
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
WAMP
- 有時,沒什么毛病,它就是不給你運行。這個迷之原因,炸了沒。別扯什么底層代理實現(xiàn)過程。
- 使用顏色分析過程,一般是:紅色->橙色->綠色。不行的話,紅色那狀態(tài)會比較快,然后停到橙色。
- 使用重復啟動法,重復重啟。當紅色停留比較久時,那就可能成功了。
4.提交方案
下面將使用Apache反向代理,使網(wǎng)頁端與API接口變成localhost間的請求,原理圖如下所示,網(wǎng)頁端服務(wù)跟API服務(wù)將在內(nèi)部服務(wù)器中:

1. 將網(wǎng)頁端服務(wù)使用反向代理出來
- Apache 配置如下所示:
標志RewriteEngine, Rewrite*, 規(guī)則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
<VirtualHost *:30003>
RewriteEngine On
RewriteCond %{HTTP:Connection} Upgrade [NC]
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteRule /(.*) ws://127.0.0.1:3030/$1 [P,L]
ProxyRequests off
<Location />
ProxyPass http://127.0.0.1:3030/
ProxyPassReverse /
</Location>
</VirtualHost>
2.前后端分離,前端使用socket.io-client,代碼如下所示:
import openSocket from 'socket.io-client';
const socket = openSocket(); //不用設(shè)置任意參數(shù)
socket.on('heartbeat', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
5.運行項目
- 訪問服務(wù)器端口30003地址,其實是反向訪問localhost:3000。localhost地址之間socket長連接無fuck。
-
不安全是Http協(xié)議的長連接。
6.參考網(wǎng)站
- 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
- 規(guī)則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設(shè)置?,不太清楚
